From 669461d60ea1893d641c2d2f7510a834e00f39f0 Mon Sep 17 00:00:00 2001 From: AnastasiiaSvietlova <119674359+AnastasiiaSvietlova@users.noreply.github.com> Date: Wed, 30 Jul 2025 10:58:25 +0200 Subject: [PATCH 01/17] Convert @bugsnag/plugin-node-device to TypeScript (#2505) * convert plugin-node-device * fix type errors and update test * fix export * made value optional * fix test * add os to rollup --- package-lock.json | 2097 +---------------- packages/plugin-node-device/package.json | 22 +- .../plugin-node-device/rollup.config.npm.mjs | 6 + .../{device.js => src/device.ts} | 11 +- .../plugin-node-device/test/device.test.ts | 10 +- packages/plugin-node-device/tsconfig.json | 8 + tsconfig.json | 1 - 7 files changed, 83 insertions(+), 2072 deletions(-) create mode 100644 packages/plugin-node-device/rollup.config.npm.mjs rename packages/plugin-node-device/{device.js => src/device.ts} (77%) create mode 100644 packages/plugin-node-device/tsconfig.json diff --git a/package-lock.json b/package-lock.json index ff6045b0ce..9cae479e36 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42018,6 +42018,13 @@ "undeclared-identifiers": "bin.js" } }, + "node_modules/undici-types": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", + "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", + "dev": true, + "license": "MIT" + }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", @@ -42283,12 +42290,6 @@ "node": ">= 0.4" } }, - "node_modules/url/node_modules/punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", - "dev": true - }, "node_modules/use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", @@ -44142,99 +44143,6 @@ "tslib": "^2.8.1" } }, - "packages/core/node_modules/@babel/compat-data": { - "version": "7.26.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", - "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "packages/core/node_modules/@babel/generator": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.10.tgz", - "integrity": "sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.26.10", - "@babel/types": "^7.26.10", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "packages/core/node_modules/@babel/helper-compilation-targets": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", - "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.26.5", - "@babel/helper-validator-option": "^7.25.9", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "packages/core/node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.3.tgz", - "integrity": "sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.22.6", - "@babel/helper-plugin-utils": "^7.22.5", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "packages/core/node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "packages/core/node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, "packages/core/node_modules/@babel/helper-plugin-utils": { "version": "7.26.5", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", @@ -44245,40 +44153,6 @@ "node": ">=6.9.0" } }, - "packages/core/node_modules/@babel/parser": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.10.tgz", - "integrity": "sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.26.10" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "packages/core/node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz", - "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", - "@babel/plugin-transform-optional-chaining": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, "packages/core/node_modules/@babel/plugin-syntax-jsx": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", @@ -44311,526 +44185,6 @@ "@babel/core": "^7.0.0-0" } }, - "packages/core/node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", - "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.26.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.26.8.tgz", - "integrity": "sha512-He9Ej2X7tNf2zdKMAGOsmg2MrFc+hfoAhd3po4cWfo/NWjzEAKa0oQruj1ROVUdl0e6fb6/kE/G3SSxE0lRJOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.26.5", - "@babel/helper-remap-async-to-generator": "^7.25.9", - "@babel/traverse": "^7.26.8" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", - "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-remap-async-to-generator": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.26.5.tgz", - "integrity": "sha512-chuTSY+hq09+/f5lMj8ZSYgCFpppV2CbYrhNFJ1BFoXpiWPnnAb7R0MqrafCpN8E1+YRrtM1MXZHJdIx8B6rMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.26.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz", - "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-classes": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", - "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-replace-supers": "^7.25.9", - "@babel/traverse": "^7.25.9", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", - "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/template": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-destructuring": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", - "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz", - "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz", - "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.26.3.tgz", - "integrity": "sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-for-of": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.26.9.tgz", - "integrity": "sha512-Hry8AusVm8LW5BVFgiyUReuoGzPUpdHQQqJY5bZnbbf+ngOHWuCuYFKw/BqaaWlvEUrF91HMhDtEaI1hZzNbLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.26.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-function-name": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", - "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/traverse": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-literals": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", - "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", - "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz", - "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz", - "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz", - "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz", - "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz", - "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-new-target": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz", - "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.26.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.26.6.tgz", - "integrity": "sha512-CKW8Vu+uUZneQCPtXmSBUC6NCAUdya26hWCElAWh5mVSlSRsmiCPUUDKb3Z0szng1hiAJa098Hkhg9o4SE35Qw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.26.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-object-super": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", - "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-replace-supers": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-property-literals": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", - "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-regenerator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz", - "integrity": "sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "regenerator-transform": "^0.15.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz", - "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", - "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-spread": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", - "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz", - "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-template-literals": { - "version": "7.26.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.26.8.tgz", - "integrity": "sha512-OmGDL5/J0CJPJZTHZbi2XpO0tyT2Ia7fzpW5GURwdtp2X3fMmN8au/ej6peC/T33/+CRiIpA8Krse8hFGVmT5Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.26.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.26.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.26.7.tgz", - "integrity": "sha512-jfoTXXZTgGg36BmhqT3cAYK5qkmqvJpvNrPhaK/52Vgjhw4Rq29s9UqpWWV0D6yuRmgiFH/BUVlkl96zJWqnaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.26.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "packages/core/node_modules/@babel/plugin-transform-typescript": { "version": "7.26.8", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.8.tgz", @@ -44851,138 +44205,6 @@ "@babel/core": "^7.0.0-0" } }, - "packages/core/node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", - "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz", - "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/preset-env": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.9.tgz", - "integrity": "sha512-vX3qPGE8sEKEAZCWk05k3cpTAE3/nOYca++JA+Rd0z2NCNzabmYvEiSShKzm10zdquOIAVXsy2Ei/DTW34KlKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.26.8", - "@babel/helper-compilation-targets": "^7.26.5", - "@babel/helper-plugin-utils": "^7.26.5", - "@babel/helper-validator-option": "^7.25.9", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", - "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.26.0", - "@babel/plugin-syntax-import-attributes": "^7.26.0", - "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.25.9", - "@babel/plugin-transform-async-generator-functions": "^7.26.8", - "@babel/plugin-transform-async-to-generator": "^7.25.9", - "@babel/plugin-transform-block-scoped-functions": "^7.26.5", - "@babel/plugin-transform-block-scoping": "^7.25.9", - "@babel/plugin-transform-class-properties": "^7.25.9", - "@babel/plugin-transform-class-static-block": "^7.26.0", - "@babel/plugin-transform-classes": "^7.25.9", - "@babel/plugin-transform-computed-properties": "^7.25.9", - "@babel/plugin-transform-destructuring": "^7.25.9", - "@babel/plugin-transform-dotall-regex": "^7.25.9", - "@babel/plugin-transform-duplicate-keys": "^7.25.9", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", - "@babel/plugin-transform-dynamic-import": "^7.25.9", - "@babel/plugin-transform-exponentiation-operator": "^7.26.3", - "@babel/plugin-transform-export-namespace-from": "^7.25.9", - "@babel/plugin-transform-for-of": "^7.26.9", - "@babel/plugin-transform-function-name": "^7.25.9", - "@babel/plugin-transform-json-strings": "^7.25.9", - "@babel/plugin-transform-literals": "^7.25.9", - "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", - "@babel/plugin-transform-member-expression-literals": "^7.25.9", - "@babel/plugin-transform-modules-amd": "^7.25.9", - "@babel/plugin-transform-modules-commonjs": "^7.26.3", - "@babel/plugin-transform-modules-systemjs": "^7.25.9", - "@babel/plugin-transform-modules-umd": "^7.25.9", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", - "@babel/plugin-transform-new-target": "^7.25.9", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.26.6", - "@babel/plugin-transform-numeric-separator": "^7.25.9", - "@babel/plugin-transform-object-rest-spread": "^7.25.9", - "@babel/plugin-transform-object-super": "^7.25.9", - "@babel/plugin-transform-optional-catch-binding": "^7.25.9", - "@babel/plugin-transform-optional-chaining": "^7.25.9", - "@babel/plugin-transform-parameters": "^7.25.9", - "@babel/plugin-transform-private-methods": "^7.25.9", - "@babel/plugin-transform-private-property-in-object": "^7.25.9", - "@babel/plugin-transform-property-literals": "^7.25.9", - "@babel/plugin-transform-regenerator": "^7.25.9", - "@babel/plugin-transform-regexp-modifiers": "^7.26.0", - "@babel/plugin-transform-reserved-words": "^7.25.9", - "@babel/plugin-transform-shorthand-properties": "^7.25.9", - "@babel/plugin-transform-spread": "^7.25.9", - "@babel/plugin-transform-sticky-regex": "^7.25.9", - "@babel/plugin-transform-template-literals": "^7.26.8", - "@babel/plugin-transform-typeof-symbol": "^7.26.7", - "@babel/plugin-transform-unicode-escapes": "^7.25.9", - "@babel/plugin-transform-unicode-property-regex": "^7.25.9", - "@babel/plugin-transform-unicode-regex": "^7.25.9", - "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", - "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.10", - "babel-plugin-polyfill-corejs3": "^0.11.0", - "babel-plugin-polyfill-regenerator": "^0.6.1", - "core-js-compat": "^3.40.0", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/core/node_modules/@babel/preset-modules": { - "version": "0.1.6-no-external-plugins", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", - "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" - } - }, "packages/core/node_modules/@babel/preset-typescript": { "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.26.0.tgz", @@ -45003,54 +44225,6 @@ "@babel/core": "^7.0.0-0" } }, - "packages/core/node_modules/@babel/template": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz", - "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/parser": "^7.26.9", - "@babel/types": "^7.26.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "packages/core/node_modules/@babel/traverse": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.10.tgz", - "integrity": "sha512-k8NuDrxr0WrPH5Aupqb2LCVURP/S0vBEn5mK6iH+GIYob66U5EtoZvcdudR2jQ4cmTwhEwW1DLB+Yyas9zjF6A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.10", - "@babel/parser": "^7.26.10", - "@babel/template": "^7.26.9", - "@babel/types": "^7.26.10", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "packages/core/node_modules/@babel/types": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.10.tgz", - "integrity": "sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, "packages/core/node_modules/@rollup/plugin-node-resolve": { "version": "16.0.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.1.tgz", @@ -45076,116 +44250,6 @@ } } }, - "packages/core/node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.12", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.12.tgz", - "integrity": "sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.6.3", - "semver": "^6.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "packages/core/node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz", - "integrity": "sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.3", - "core-js-compat": "^3.40.0" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "packages/core/node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.3.tgz", - "integrity": "sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.3" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "packages/core/node_modules/browserslist": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", - "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "caniuse-lite": "^1.0.30001688", - "electron-to-chromium": "^1.5.73", - "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.1" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "packages/core/node_modules/caniuse-lite": { - "version": "1.0.30001706", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001706.tgz", - "integrity": "sha512-3ZczoTApMAZwPKYWmwVbQMFpXBDds3/0VciVoUwPUbldlYyVLmRVuRs/PcUZtHpbLRpzzDvrvnFuREsGt6lUug==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "packages/core/node_modules/core-js-compat": { - "version": "3.41.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.41.0.tgz", - "integrity": "sha512-RFsU9LySVue9RTwdDVX/T0e2Y6jRYWXERKElIjpuEOEnxaXffI0X7RUwVzfYLfzuLXSNJDYoRYUAmRUcyln20A==", - "dev": true, - "license": "MIT", - "dependencies": { - "browserslist": "^4.24.4" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, "packages/core/node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -45196,43 +44260,6 @@ "node": ">=0.10.0" } }, - "packages/core/node_modules/electron-to-chromium": { - "version": "1.5.120", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.120.tgz", - "integrity": "sha512-oTUp3gfX1gZI+xfD2djr2rzQdHCwHzPQrrK0CD7WpTdF0nPdQ/INcRVjWgLdCT4a9W3jFObR9DAfsuyFQnI8CQ==", - "dev": true, - "license": "ISC" - }, - "packages/core/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "packages/core/node_modules/regenerator-transform": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", - "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, - "packages/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "packages/core/node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -47108,16 +46135,6 @@ "zone.js": "~0.15.0" } }, - "packages/plugin-angular/node_modules/@babel/compat-data": { - "version": "7.26.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", - "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, "packages/plugin-angular/node_modules/@babel/core": { "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", @@ -47179,80 +46196,6 @@ "node": ">=6.9.0" } }, - "packages/plugin-angular/node_modules/@babel/helper-compilation-targets": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", - "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.26.5", - "@babel/helper-validator-option": "^7.25.9", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "packages/plugin-angular/node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "packages/plugin-angular/node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "packages/plugin-angular/node_modules/@babel/helper-compilation-targets/node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, - "packages/plugin-angular/node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "packages/plugin-angular/node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, "packages/plugin-angular/node_modules/@babel/helper-split-export-declaration": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", @@ -47266,118 +46209,6 @@ "node": ">=6.9.0" } }, - "packages/plugin-angular/node_modules/@babel/helpers": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.10.tgz", - "integrity": "sha512-UPYc3SauzZ3JGgj87GgZ89JVdC5dj0AoetR5Bw6wj4niittNyFh6+eOGonYvJ1ao6B8lEa3Q3klS7ADZ53bc5g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.26.9", - "@babel/types": "^7.26.10" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "packages/plugin-angular/node_modules/@babel/parser": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.10.tgz", - "integrity": "sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.26.10" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "packages/plugin-angular/node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", - "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-remap-async-to-generator": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "packages/plugin-angular/node_modules/@babel/template": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz", - "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/parser": "^7.26.9", - "@babel/types": "^7.26.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "packages/plugin-angular/node_modules/@babel/traverse": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.10.tgz", - "integrity": "sha512-k8NuDrxr0WrPH5Aupqb2LCVURP/S0vBEn5mK6iH+GIYob66U5EtoZvcdudR2jQ4cmTwhEwW1DLB+Yyas9zjF6A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.10", - "@babel/parser": "^7.26.10", - "@babel/template": "^7.26.9", - "@babel/types": "^7.26.10", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "packages/plugin-angular/node_modules/@babel/traverse/node_modules/@babel/generator": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.10.tgz", - "integrity": "sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.26.10", - "@babel/types": "^7.26.10", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "packages/plugin-angular/node_modules/@babel/types": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.10.tgz", - "integrity": "sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, "packages/plugin-angular/node_modules/@discoveryjs/json-ext": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz", @@ -47409,15 +46240,6 @@ } } }, - "packages/plugin-angular/node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "packages/plugin-angular/node_modules/@ngtools/webpack": { "version": "19.2.14", "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-19.2.14.tgz", @@ -47954,23 +46776,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "packages/plugin-angular/node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, "packages/plugin-angular/node_modules/figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", @@ -48023,16 +46828,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "packages/plugin-angular/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "packages/plugin-angular/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -48238,19 +47033,6 @@ "node": ">=12" } }, - "packages/plugin-angular/node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, "packages/plugin-angular/node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -48791,25 +47573,6 @@ "node": ">=8" } }, - "packages/plugin-angular/node_modules/terser": { - "version": "5.37.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.37.0.tgz", - "integrity": "sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, "packages/plugin-angular/node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -49470,12 +48233,23 @@ "version": "8.4.0", "license": "MIT", "devDependencies": { - "@bugsnag/core": "^8.4.0" + "@bugsnag/core": "^8.4.0", + "@types/node": "^18.19.74" }, "peerDependencies": { "@bugsnag/core": "^8.0.0" } }, + "packages/plugin-node-device/node_modules/@types/node": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.1.0.tgz", + "integrity": "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.8.0" + } + }, "packages/plugin-node-in-project": { "name": "@bugsnag/plugin-node-in-project", "version": "8.4.0", @@ -51629,98 +50403,12 @@ "tslib": "^2.8.1" }, "dependencies": { - "@babel/compat-data": { - "version": "7.26.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", - "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", - "dev": true - }, - "@babel/generator": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.10.tgz", - "integrity": "sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang==", - "dev": true, - "requires": { - "@babel/parser": "^7.26.10", - "@babel/types": "^7.26.10", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^3.0.2" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", - "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.26.5", - "@babel/helper-validator-option": "^7.25.9", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - } - }, - "@babel/helper-define-polyfill-provider": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.3.tgz", - "integrity": "sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg==", - "dev": true, - "requires": { - "@babel/helper-compilation-targets": "^7.22.6", - "@babel/helper-plugin-utils": "^7.22.5", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2" - } - }, - "@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", - "dev": true, - "requires": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" - } - }, - "@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" - } - }, "@babel/helper-plugin-utils": { "version": "7.26.5", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", "dev": true }, - "@babel/parser": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.10.tgz", - "integrity": "sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==", - "dev": true, - "requires": { - "@babel/types": "^7.26.10" - } - }, - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz", - "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", - "@babel/plugin-transform-optional-chaining": "^7.25.9" - } - }, "@babel/plugin-syntax-jsx": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", @@ -51739,309 +50427,6 @@ "@babel/helper-plugin-utils": "^7.25.9" } }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", - "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.25.9" - } - }, - "@babel/plugin-transform-async-generator-functions": { - "version": "7.26.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.26.8.tgz", - "integrity": "sha512-He9Ej2X7tNf2zdKMAGOsmg2MrFc+hfoAhd3po4cWfo/NWjzEAKa0oQruj1ROVUdl0e6fb6/kE/G3SSxE0lRJOg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.26.5", - "@babel/helper-remap-async-to-generator": "^7.25.9", - "@babel/traverse": "^7.26.8" - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", - "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-remap-async-to-generator": "^7.25.9" - } - }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.26.5.tgz", - "integrity": "sha512-chuTSY+hq09+/f5lMj8ZSYgCFpppV2CbYrhNFJ1BFoXpiWPnnAb7R0MqrafCpN8E1+YRrtM1MXZHJdIx8B6rMQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.26.5" - } - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz", - "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.25.9" - } - }, - "@babel/plugin-transform-classes": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", - "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-replace-supers": "^7.25.9", - "@babel/traverse": "^7.25.9", - "globals": "^11.1.0" - } - }, - "@babel/plugin-transform-computed-properties": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", - "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/template": "^7.25.9" - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", - "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.25.9" - } - }, - "@babel/plugin-transform-dotall-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz", - "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" - } - }, - "@babel/plugin-transform-duplicate-keys": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz", - "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.25.9" - } - }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.26.3.tgz", - "integrity": "sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.25.9" - } - }, - "@babel/plugin-transform-for-of": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.26.9.tgz", - "integrity": "sha512-Hry8AusVm8LW5BVFgiyUReuoGzPUpdHQQqJY5bZnbbf+ngOHWuCuYFKw/BqaaWlvEUrF91HMhDtEaI1hZzNbLg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.26.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" - } - }, - "@babel/plugin-transform-function-name": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", - "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", - "dev": true, - "requires": { - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/traverse": "^7.25.9" - } - }, - "@babel/plugin-transform-literals": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", - "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.25.9" - } - }, - "@babel/plugin-transform-member-expression-literals": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", - "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.25.9" - } - }, - "@babel/plugin-transform-modules-amd": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz", - "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" - } - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz", - "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helper-plugin-utils": "^7.25.9" - } - }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz", - "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" - } - }, - "@babel/plugin-transform-modules-umd": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz", - "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" - } - }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz", - "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" - } - }, - "@babel/plugin-transform-new-target": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz", - "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.25.9" - } - }, - "@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.26.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.26.6.tgz", - "integrity": "sha512-CKW8Vu+uUZneQCPtXmSBUC6NCAUdya26hWCElAWh5mVSlSRsmiCPUUDKb3Z0szng1hiAJa098Hkhg9o4SE35Qw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.26.5" - } - }, - "@babel/plugin-transform-object-super": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", - "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-replace-supers": "^7.25.9" - } - }, - "@babel/plugin-transform-property-literals": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", - "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.25.9" - } - }, - "@babel/plugin-transform-regenerator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz", - "integrity": "sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.25.9", - "regenerator-transform": "^0.15.2" - } - }, - "@babel/plugin-transform-reserved-words": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz", - "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.25.9" - } - }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", - "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.25.9" - } - }, - "@babel/plugin-transform-spread": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", - "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" - } - }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz", - "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.25.9" - } - }, - "@babel/plugin-transform-template-literals": { - "version": "7.26.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.26.8.tgz", - "integrity": "sha512-OmGDL5/J0CJPJZTHZbi2XpO0tyT2Ia7fzpW5GURwdtp2X3fMmN8au/ej6peC/T33/+CRiIpA8Krse8hFGVmT5Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.26.5" - } - }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.26.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.26.7.tgz", - "integrity": "sha512-jfoTXXZTgGg36BmhqT3cAYK5qkmqvJpvNrPhaK/52Vgjhw4Rq29s9UqpWWV0D6yuRmgiFH/BUVlkl96zJWqnaw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.26.5" - } - }, "@babel/plugin-transform-typescript": { "version": "7.26.8", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.8.tgz", @@ -52055,113 +50440,6 @@ "@babel/plugin-syntax-typescript": "^7.25.9" } }, - "@babel/plugin-transform-unicode-escapes": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", - "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.25.9" - } - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz", - "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" - } - }, - "@babel/preset-env": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.9.tgz", - "integrity": "sha512-vX3qPGE8sEKEAZCWk05k3cpTAE3/nOYca++JA+Rd0z2NCNzabmYvEiSShKzm10zdquOIAVXsy2Ei/DTW34KlKQ==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.26.8", - "@babel/helper-compilation-targets": "^7.26.5", - "@babel/helper-plugin-utils": "^7.26.5", - "@babel/helper-validator-option": "^7.25.9", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", - "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.26.0", - "@babel/plugin-syntax-import-attributes": "^7.26.0", - "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.25.9", - "@babel/plugin-transform-async-generator-functions": "^7.26.8", - "@babel/plugin-transform-async-to-generator": "^7.25.9", - "@babel/plugin-transform-block-scoped-functions": "^7.26.5", - "@babel/plugin-transform-block-scoping": "^7.25.9", - "@babel/plugin-transform-class-properties": "^7.25.9", - "@babel/plugin-transform-class-static-block": "^7.26.0", - "@babel/plugin-transform-classes": "^7.25.9", - "@babel/plugin-transform-computed-properties": "^7.25.9", - "@babel/plugin-transform-destructuring": "^7.25.9", - "@babel/plugin-transform-dotall-regex": "^7.25.9", - "@babel/plugin-transform-duplicate-keys": "^7.25.9", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", - "@babel/plugin-transform-dynamic-import": "^7.25.9", - "@babel/plugin-transform-exponentiation-operator": "^7.26.3", - "@babel/plugin-transform-export-namespace-from": "^7.25.9", - "@babel/plugin-transform-for-of": "^7.26.9", - "@babel/plugin-transform-function-name": "^7.25.9", - "@babel/plugin-transform-json-strings": "^7.25.9", - "@babel/plugin-transform-literals": "^7.25.9", - "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", - "@babel/plugin-transform-member-expression-literals": "^7.25.9", - "@babel/plugin-transform-modules-amd": "^7.25.9", - "@babel/plugin-transform-modules-commonjs": "^7.26.3", - "@babel/plugin-transform-modules-systemjs": "^7.25.9", - "@babel/plugin-transform-modules-umd": "^7.25.9", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", - "@babel/plugin-transform-new-target": "^7.25.9", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.26.6", - "@babel/plugin-transform-numeric-separator": "^7.25.9", - "@babel/plugin-transform-object-rest-spread": "^7.25.9", - "@babel/plugin-transform-object-super": "^7.25.9", - "@babel/plugin-transform-optional-catch-binding": "^7.25.9", - "@babel/plugin-transform-optional-chaining": "^7.25.9", - "@babel/plugin-transform-parameters": "^7.25.9", - "@babel/plugin-transform-private-methods": "^7.25.9", - "@babel/plugin-transform-private-property-in-object": "^7.25.9", - "@babel/plugin-transform-property-literals": "^7.25.9", - "@babel/plugin-transform-regenerator": "^7.25.9", - "@babel/plugin-transform-regexp-modifiers": "^7.26.0", - "@babel/plugin-transform-reserved-words": "^7.25.9", - "@babel/plugin-transform-shorthand-properties": "^7.25.9", - "@babel/plugin-transform-spread": "^7.25.9", - "@babel/plugin-transform-sticky-regex": "^7.25.9", - "@babel/plugin-transform-template-literals": "^7.26.8", - "@babel/plugin-transform-typeof-symbol": "^7.26.7", - "@babel/plugin-transform-unicode-escapes": "^7.25.9", - "@babel/plugin-transform-unicode-property-regex": "^7.25.9", - "@babel/plugin-transform-unicode-regex": "^7.25.9", - "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", - "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.10", - "babel-plugin-polyfill-corejs3": "^0.11.0", - "babel-plugin-polyfill-regenerator": "^0.6.1", - "core-js-compat": "^3.40.0", - "semver": "^6.3.1" - } - }, - "@babel/preset-modules": { - "version": "0.1.6-no-external-plugins", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", - "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - } - }, "@babel/preset-typescript": { "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.26.0.tgz", @@ -52175,42 +50453,6 @@ "@babel/plugin-transform-typescript": "^7.25.9" } }, - "@babel/template": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz", - "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.26.2", - "@babel/parser": "^7.26.9", - "@babel/types": "^7.26.9" - } - }, - "@babel/traverse": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.10.tgz", - "integrity": "sha512-k8NuDrxr0WrPH5Aupqb2LCVURP/S0vBEn5mK6iH+GIYob66U5EtoZvcdudR2jQ4cmTwhEwW1DLB+Yyas9zjF6A==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.10", - "@babel/parser": "^7.26.10", - "@babel/template": "^7.26.9", - "@babel/types": "^7.26.10", - "debug": "^4.3.1", - "globals": "^11.1.0" - } - }, - "@babel/types": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.10.tgz", - "integrity": "sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" - } - }, "@rollup/plugin-node-resolve": { "version": "16.0.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.1.tgz", @@ -52224,96 +50466,12 @@ "resolve": "^1.22.1" } }, - "babel-plugin-polyfill-corejs2": { - "version": "0.4.12", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.12.tgz", - "integrity": "sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.6.3", - "semver": "^6.3.1" - } - }, - "babel-plugin-polyfill-corejs3": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz", - "integrity": "sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==", - "dev": true, - "requires": { - "@babel/helper-define-polyfill-provider": "^0.6.3", - "core-js-compat": "^3.40.0" - } - }, - "babel-plugin-polyfill-regenerator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.3.tgz", - "integrity": "sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q==", - "dev": true, - "requires": { - "@babel/helper-define-polyfill-provider": "^0.6.3" - } - }, - "browserslist": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", - "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001688", - "electron-to-chromium": "^1.5.73", - "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.1" - } - }, - "caniuse-lite": { - "version": "1.0.30001706", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001706.tgz", - "integrity": "sha512-3ZczoTApMAZwPKYWmwVbQMFpXBDds3/0VciVoUwPUbldlYyVLmRVuRs/PcUZtHpbLRpzzDvrvnFuREsGt6lUug==", - "dev": true - }, - "core-js-compat": { - "version": "3.41.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.41.0.tgz", - "integrity": "sha512-RFsU9LySVue9RTwdDVX/T0e2Y6jRYWXERKElIjpuEOEnxaXffI0X7RUwVzfYLfzuLXSNJDYoRYUAmRUcyln20A==", - "dev": true, - "requires": { - "browserslist": "^4.24.4" - } - }, "deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true }, - "electron-to-chromium": { - "version": "1.5.120", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.120.tgz", - "integrity": "sha512-oTUp3gfX1gZI+xfD2djr2rzQdHCwHzPQrrK0CD7WpTdF0nPdQ/INcRVjWgLdCT4a9W3jFObR9DAfsuyFQnI8CQ==", - "dev": true - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "regenerator-transform": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", - "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", - "dev": true, - "requires": { - "@babel/runtime": "^7.8.4" - } - }, - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - }, "tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -53380,12 +51538,6 @@ "tslib": "^2.3.0" } }, - "@babel/compat-data": { - "version": "7.26.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", - "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", - "dev": true - }, "@babel/core": { "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", @@ -53436,63 +51588,6 @@ "jsesc": "^3.0.2" } }, - "@babel/helper-compilation-targets": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", - "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.26.5", - "@babel/helper-validator-option": "^7.25.9", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "dependencies": { - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "requires": { - "yallist": "^3.0.2" - } - }, - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - } - } - }, - "@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", - "dev": true, - "requires": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" - } - }, - "@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" - } - }, "@babel/helper-split-export-declaration": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", @@ -53502,87 +51597,6 @@ "@babel/types": "^7.24.7" } }, - "@babel/helpers": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.10.tgz", - "integrity": "sha512-UPYc3SauzZ3JGgj87GgZ89JVdC5dj0AoetR5Bw6wj4niittNyFh6+eOGonYvJ1ao6B8lEa3Q3klS7ADZ53bc5g==", - "dev": true, - "requires": { - "@babel/template": "^7.26.9", - "@babel/types": "^7.26.10" - } - }, - "@babel/parser": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.10.tgz", - "integrity": "sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==", - "dev": true, - "requires": { - "@babel/types": "^7.26.10" - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", - "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-remap-async-to-generator": "^7.25.9" - } - }, - "@babel/template": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz", - "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.26.2", - "@babel/parser": "^7.26.9", - "@babel/types": "^7.26.9" - } - }, - "@babel/traverse": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.10.tgz", - "integrity": "sha512-k8NuDrxr0WrPH5Aupqb2LCVURP/S0vBEn5mK6iH+GIYob66U5EtoZvcdudR2jQ4cmTwhEwW1DLB+Yyas9zjF6A==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.10", - "@babel/parser": "^7.26.10", - "@babel/template": "^7.26.9", - "@babel/types": "^7.26.10", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "dependencies": { - "@babel/generator": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.10.tgz", - "integrity": "sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang==", - "dev": true, - "requires": { - "@babel/parser": "^7.26.10", - "@babel/types": "^7.26.10", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^3.0.2" - } - } - } - }, - "@babel/types": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.10.tgz", - "integrity": "sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" - } - }, "@discoveryjs/json-ext": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz", @@ -53599,12 +51613,6 @@ "@inquirer/type": "^3.0.4" } }, - "@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, "@ngtools/webpack": { "version": "19.2.14", "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-19.2.14.tgz", @@ -53929,19 +51937,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - } - }, "figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", @@ -53976,12 +51971,6 @@ "path-scurry": "^1.11.1" } }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -54138,16 +52127,6 @@ "@jridgewell/sourcemap-codec": "^1.4.15" } }, - "micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "requires": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - } - }, "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -54518,18 +52497,6 @@ "has-flag": "^4.0.0" } }, - "terser": { - "version": "5.37.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.37.0.tgz", - "integrity": "sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==", - "dev": true, - "requires": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - } - }, "tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -54956,7 +52923,18 @@ "@bugsnag/plugin-node-device": { "version": "file:packages/plugin-node-device", "requires": { - "@bugsnag/core": "^8.4.0" + "@bugsnag/core": "^8.4.0", + "@types/node": "^18.19.74" + }, + "dependencies": { + "@types/node": { + "version": "https://registry.npmjs.org/@types/node/-/node-24.1.0.tgz", + "integrity": "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==", + "dev": true, + "requires": { + "undici-types": "~7.8.0" + } + } } }, "@bugsnag/plugin-node-in-project": { @@ -84255,6 +82233,12 @@ "xtend": "^4.0.1" } }, + "undici-types": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", + "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", + "dev": true + }, "unicode-canonical-property-names-ecmascript": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", @@ -84447,13 +82431,6 @@ "requires": { "punycode": "^1.4.1", "qs": "^6.12.3" - }, - "dependencies": { - "punycode": { - "version": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", - "dev": true - } } }, "use": { diff --git a/packages/plugin-node-device/package.json b/packages/plugin-node-device/package.json index 57b2746eb3..d2f65fe966 100644 --- a/packages/plugin-node-device/package.json +++ b/packages/plugin-node-device/package.json @@ -1,7 +1,15 @@ { "name": "@bugsnag/plugin-node-device", "version": "8.4.0", - "main": "device.js", + "main": "dist/device.js", + "types": "dist/types/device.d.ts", + "exports": { + ".": { + "types": "./dist/types/device.d.ts", + "default": "./dist/device.js", + "import": "./dist/device.mjs" + } + }, "description": "@bugsnag/js plugin to set device info in node", "homepage": "https://www.bugsnag.com/", "repository": { @@ -12,15 +20,21 @@ "access": "public" }, "files": [ - "*.js" + "dist" ], - "scripts": {}, "author": "Bugsnag", "license": "MIT", "devDependencies": { - "@bugsnag/core": "^8.4.0" + "@bugsnag/core": "^8.4.0", + "@types/node": "^18.19.74" }, "peerDependencies": { "@bugsnag/core": "^8.0.0" + }, + "scripts": { + "build": "npm run build:npm", + "build:npm": "rollup --config rollup.config.npm.mjs", + "clean": "rm -rf dist/*", + "test:types": "tsc -p tsconfig.json" } } diff --git a/packages/plugin-node-device/rollup.config.npm.mjs b/packages/plugin-node-device/rollup.config.npm.mjs new file mode 100644 index 0000000000..f31dcbe15d --- /dev/null +++ b/packages/plugin-node-device/rollup.config.npm.mjs @@ -0,0 +1,6 @@ +import createRollupConfig from "../../.rollup/index.mjs"; + +export default createRollupConfig({ + input: "src/device.ts", + external: ["os"], +}); \ No newline at end of file diff --git a/packages/plugin-node-device/device.js b/packages/plugin-node-device/src/device.ts similarity index 77% rename from packages/plugin-node-device/device.js rename to packages/plugin-node-device/src/device.ts index 46f4b84d83..455104b062 100644 --- a/packages/plugin-node-device/device.js +++ b/packages/plugin-node-device/src/device.ts @@ -1,9 +1,14 @@ -const os = require('os') +import { Config, Plugin } from '@bugsnag/core' +import os from 'os' + +export interface PluginConfig extends Config { + hostname?: string +} /* * Automatically detects Node server details ('device' in the API) */ -module.exports = { +const plugin: Plugin = { load: (client) => { const device = { osName: `${os.platform()} (${os.arch()})`, @@ -31,3 +36,5 @@ module.exports = { }, true) } } + +export default plugin \ No newline at end of file diff --git a/packages/plugin-node-device/test/device.test.ts b/packages/plugin-node-device/test/device.test.ts index e3a7a939c8..6bd66102c4 100644 --- a/packages/plugin-node-device/test/device.test.ts +++ b/packages/plugin-node-device/test/device.test.ts @@ -1,8 +1,8 @@ -import plugin from '../device' -import { Client } from '@bugsnag/core' +import plugin from '../src/device' +import { Client, schema as coreSchema } from '@bugsnag/core' const schema = { - ...require('@bugsnag/core').schema, + ...coreSchema, hostname: { defaultValue: () => 'test-machine.local', validate: () => true, @@ -12,12 +12,12 @@ const schema = { describe('plugin: node device', () => { it('should set device = { hostname, runtimeVersions } add an onError callback which adds device time', done => { - const client = new Client({ apiKey: 'API_KEY_YEAH', plugins: [plugin] }, schema) + const client = new Client({ apiKey: 'API_KEY_YEAH', plugins: [plugin]}, schema) expect(client._cbs.sp.length).toBe(1) expect(client._cbs.e.length).toBe(1) - client._setDelivery(client => ({ + client._setDelivery(() => ({ sendEvent: (payload) => { expect(payload.events[0].device).toBeDefined() expect(payload.events[0].device.time instanceof Date).toBe(true) diff --git a/packages/plugin-node-device/tsconfig.json b/packages/plugin-node-device/tsconfig.json new file mode 100644 index 0000000000..66a7db7b94 --- /dev/null +++ b/packages/plugin-node-device/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": { + "lib": ["es2017"], + "types": ["node"] + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 4ab55f2541..be0721a5f6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -33,7 +33,6 @@ "packages/plugin-intercept", "packages/plugin-node-unhandled-rejection", "packages/plugin-node-in-project", - "packages/plugin-node-device", "packages/plugin-node-surrounding-code", "packages/plugin-node-uncaught-exception", "packages/browser" From ac307468fb8abf18eb587cf16cb2e71f685aac75 Mon Sep 17 00:00:00 2001 From: AnastasiiaSvietlova <119674359+AnastasiiaSvietlova@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:14:54 +0200 Subject: [PATCH 02/17] Convert @bugsnag/plugin-node-in-project to TypeScript (#2506) * convert plugin-node-in-project * fix types and rollup config * update rollup * update package json --- package-lock.json | 4 ++++ packages/plugin-node-in-project/package.json | 22 ++++++++++++++++--- .../rollup.config.npm.mjs | 6 +++++ .../{in-project.js => src/in-project.ts} | 13 ++++++++--- .../test/in-project.test.ts | 2 +- packages/plugin-node-in-project/tsconfig.json | 8 +++++++ tsconfig.json | 1 - 7 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 packages/plugin-node-in-project/rollup.config.npm.mjs rename packages/plugin-node-in-project/{in-project.js => src/in-project.ts} (51%) create mode 100644 packages/plugin-node-in-project/tsconfig.json diff --git a/package-lock.json b/package-lock.json index 9cae479e36..1550b3452b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48256,6 +48256,9 @@ "license": "MIT", "dependencies": { "@bugsnag/path-normalizer": "^8.4.0" + }, + "devDependencies": { + "@bugsnag/core": "^8.4.0" } }, "packages/plugin-node-surrounding-code": { @@ -52940,6 +52943,7 @@ "@bugsnag/plugin-node-in-project": { "version": "file:packages/plugin-node-in-project", "requires": { + "@bugsnag/core": "^8.4.0", "@bugsnag/path-normalizer": "^8.4.0" } }, diff --git a/packages/plugin-node-in-project/package.json b/packages/plugin-node-in-project/package.json index 717c9de9a9..23f6ec7d38 100644 --- a/packages/plugin-node-in-project/package.json +++ b/packages/plugin-node-in-project/package.json @@ -1,7 +1,15 @@ { "name": "@bugsnag/plugin-node-in-project", "version": "8.4.0", - "main": "in-project.js", + "main": "dist/in-project.js", + "types": "dist/types/in-project.d.ts", + "exports": { + ".": { + "types": "./dist/types/in-project.d.ts", + "default": "./dist/in-project.js", + "import": "./dist/in-project.mjs" + } + }, "description": "@bugsnag/js plugin to mark whether stackframes are 'in-project'", "homepage": "https://www.bugsnag.com/", "repository": { @@ -12,12 +20,20 @@ "access": "public" }, "files": [ - "*.js" + "dist" ], - "scripts": {}, "author": "Bugsnag", "license": "MIT", "dependencies": { "@bugsnag/path-normalizer": "^8.4.0" + }, + "devDependencies": { + "@bugsnag/core": "^8.4.0" + }, + "scripts": { + "build": "npm run build:npm", + "build:npm": "rollup --config rollup.config.npm.mjs", + "clean": "rm -rf dist/*", + "test:types": "tsc -p tsconfig.json" } } diff --git a/packages/plugin-node-in-project/rollup.config.npm.mjs b/packages/plugin-node-in-project/rollup.config.npm.mjs new file mode 100644 index 0000000000..721e93ee8c --- /dev/null +++ b/packages/plugin-node-in-project/rollup.config.npm.mjs @@ -0,0 +1,6 @@ +import createRollupConfig from "../../.rollup/index.mjs"; + +export default createRollupConfig({ + input: "src/in-project.ts", + external: ["@bugsnag/path-normalizer"], +}); \ No newline at end of file diff --git a/packages/plugin-node-in-project/in-project.js b/packages/plugin-node-in-project/src/in-project.ts similarity index 51% rename from packages/plugin-node-in-project/in-project.js rename to packages/plugin-node-in-project/src/in-project.ts index f056ea5b2f..74adca061e 100644 --- a/packages/plugin-node-in-project/in-project.js +++ b/packages/plugin-node-in-project/src/in-project.ts @@ -1,10 +1,15 @@ -const normalizePath = require('@bugsnag/path-normalizer') +import { Config, Plugin, Stackframe } from '@bugsnag/core' +import normalizePath from '@bugsnag/path-normalizer' -module.exports = { +interface PluginConfig extends Config { + projectRoot?: string +} + +const plugin: Plugin = { load: client => client.addOnError(event => { if (!client._config.projectRoot) return const projectRoot = normalizePath(client._config.projectRoot) - const allFrames = event.errors.reduce((accum, er) => accum.concat(er.stacktrace), []) + const allFrames: Stackframe[]= event.errors.reduce((accum: Stackframe[], er) => accum.concat(er.stacktrace), []) allFrames.map(stackframe => { stackframe.inProject = typeof stackframe.file === 'string' && stackframe.file.indexOf(projectRoot) === 0 && @@ -12,3 +17,5 @@ module.exports = { }) }) } + +export default plugin \ No newline at end of file diff --git a/packages/plugin-node-in-project/test/in-project.test.ts b/packages/plugin-node-in-project/test/in-project.test.ts index a4e38d0ea6..f8d5322221 100644 --- a/packages/plugin-node-in-project/test/in-project.test.ts +++ b/packages/plugin-node-in-project/test/in-project.test.ts @@ -1,4 +1,4 @@ -import plugin from '../' +import plugin from '../src/in-project' import { join } from 'path' import { Client, Event, schema } from '@bugsnag/core' diff --git a/packages/plugin-node-in-project/tsconfig.json b/packages/plugin-node-in-project/tsconfig.json new file mode 100644 index 0000000000..66a7db7b94 --- /dev/null +++ b/packages/plugin-node-in-project/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": { + "lib": ["es2017"], + "types": ["node"] + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index be0721a5f6..b6d1c89c57 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -32,7 +32,6 @@ "packages/plugin-interaction-breadcrumbs", "packages/plugin-intercept", "packages/plugin-node-unhandled-rejection", - "packages/plugin-node-in-project", "packages/plugin-node-surrounding-code", "packages/plugin-node-uncaught-exception", "packages/browser" From 46cc5fbd71546917a4f431ed20e9d70cb0fd5d08 Mon Sep 17 00:00:00 2001 From: AnastasiiaSvietlova <119674359+AnastasiiaSvietlova@users.noreply.github.com> Date: Thu, 7 Aug 2025 13:02:16 +0200 Subject: [PATCH 03/17] Convert @bugsnag/plugin-node-uncaught-exception to TypeScript (#2509) * convert uncaught-exception to typescript * update types * update package json * update build --- .../package.json | 19 +++++-- .../rollup.config.npm.mjs | 6 +++ .../src/uncaught-exception.ts | 50 +++++++++++++++++++ .../test/uncaught-exception.test.ts | 14 ++++-- .../tsconfig.json | 8 +++ .../uncaught-exception.js | 35 ------------- tsconfig.json | 1 - 7 files changed, 90 insertions(+), 43 deletions(-) create mode 100644 packages/plugin-node-uncaught-exception/rollup.config.npm.mjs create mode 100644 packages/plugin-node-uncaught-exception/src/uncaught-exception.ts create mode 100644 packages/plugin-node-uncaught-exception/tsconfig.json delete mode 100644 packages/plugin-node-uncaught-exception/uncaught-exception.js diff --git a/packages/plugin-node-uncaught-exception/package.json b/packages/plugin-node-uncaught-exception/package.json index 7df190b307..c8dd576cb2 100644 --- a/packages/plugin-node-uncaught-exception/package.json +++ b/packages/plugin-node-uncaught-exception/package.json @@ -1,7 +1,15 @@ { "name": "@bugsnag/plugin-node-uncaught-exception", "version": "8.4.0", - "main": "uncaught-exception.js", + "main": "dist/uncaught-exception.js", + "types": "dist/types/uncaught-exception.d.ts", + "exports": { + ".": { + "types": "./dist/types/uncaught-exception.d.ts", + "default": "./dist/uncaught-exception.js", + "import": "./dist/uncaught-exception.mjs" + } + }, "description": "@bugsnag/js plugin to capture and report uncaught exceptions", "homepage": "https://www.bugsnag.com/", "repository": { @@ -12,9 +20,8 @@ "access": "public" }, "files": [ - "*.js" + "dist" ], - "scripts": {}, "author": "Bugsnag", "license": "MIT", "devDependencies": { @@ -22,5 +29,11 @@ }, "peerDependencies": { "@bugsnag/core": "^8.0.0" + }, + "scripts": { + "build": "npm run build:npm", + "build:npm": "rollup --config rollup.config.npm.mjs", + "clean": "rm -rf dist/*", + "test:types": "tsc -p tsconfig.json" } } diff --git a/packages/plugin-node-uncaught-exception/rollup.config.npm.mjs b/packages/plugin-node-uncaught-exception/rollup.config.npm.mjs new file mode 100644 index 0000000000..e58e0eddbb --- /dev/null +++ b/packages/plugin-node-uncaught-exception/rollup.config.npm.mjs @@ -0,0 +1,6 @@ +import createRollupConfig from "../../.rollup/index.mjs" + +export default createRollupConfig({ + input: "src/uncaught-exception.ts", + external: ['async_hooks'], +}) \ No newline at end of file diff --git a/packages/plugin-node-uncaught-exception/src/uncaught-exception.ts b/packages/plugin-node-uncaught-exception/src/uncaught-exception.ts new file mode 100644 index 0000000000..e907f191a5 --- /dev/null +++ b/packages/plugin-node-uncaught-exception/src/uncaught-exception.ts @@ -0,0 +1,50 @@ +import { Client, Event, Logger, nodeFallbackStack, Plugin } from '@bugsnag/core' +import { AsyncLocalStorage } from 'async_hooks' + +interface InternalClient extends Client { + _clientContext: AsyncLocalStorage + fallbackStack?: string + _config: Client['_config'] & { + onUncaughtException: (err: Error, event: Event, logger: Logger) => void + } +} + +let _handler: ((err: Error) => Promise) | undefined +const plugin: Plugin = { + load: (client) => { + const internalClient = client as InternalClient + + if (!internalClient._config.autoDetectErrors) return + if (!internalClient._config.enabledErrorTypes.unhandledExceptions) return + _handler = (err: Error) => { + // if we are in an async context, use the client from that context + const ctx = internalClient._clientContext && internalClient._clientContext.getStore() + const c = (ctx || internalClient) as InternalClient + + // check if the stacktrace has no context, if so append the frames we created earlier + // see plugin-contextualize for where this is created + if (err.stack && c.fallbackStack) nodeFallbackStack.maybeUseFallbackStack(err, c.fallbackStack) + + const event = c.Event.create(err, false, { + severity: 'error', + unhandled: true, + severityReason: { type: 'unhandledException' } + }, 'uncaughtException handler', 1) + return new Promise(resolve => { + c._notify(event, () => {}, (e: Error | null | undefined, event: Event) => { + if (e) c._logger.error('Failed to send event to Bugsnag') + c._config.onUncaughtException(err, event, c._logger) + resolve() + }) + }) + } + process.prependListener('uncaughtException', _handler) + }, + destroy: () => { + if (_handler) { + process.removeListener('uncaughtException', _handler) + } + } +} + +export default plugin diff --git a/packages/plugin-node-uncaught-exception/test/uncaught-exception.test.ts b/packages/plugin-node-uncaught-exception/test/uncaught-exception.test.ts index 6b03da0022..2e764ef1fb 100644 --- a/packages/plugin-node-uncaught-exception/test/uncaught-exception.test.ts +++ b/packages/plugin-node-uncaught-exception/test/uncaught-exception.test.ts @@ -1,5 +1,5 @@ import { Client, Event, schema } from '@bugsnag/core' -import plugin from '../' +import plugin from '../src/uncaught-exception' describe('plugin: node uncaught exception handler', () => { it('should listen to the process#uncaughtException event', () => { @@ -8,7 +8,9 @@ describe('plugin: node uncaught exception handler', () => { const after = process.listeners('uncaughtException').length expect(after - before).toBe(1) expect(c).toBe(c) - plugin.destroy() + if (typeof plugin.destroy === 'function') { + plugin.destroy() + } }) it('does not add a process#uncaughtException listener when autoDetectErrors=false', () => { @@ -40,7 +42,9 @@ describe('plugin: node uncaught exception handler', () => { expect(event._handledState.unhandled).toBe(true) expect(event._handledState.severity).toBe('error') expect(event._handledState.severityReason).toEqual({ type: 'unhandledException' }) - plugin.destroy() + if (typeof plugin.destroy === 'function') { + plugin.destroy() + } done() }, plugins: [plugin] @@ -69,7 +73,9 @@ describe('plugin: node uncaught exception handler', () => { expect(event._handledState.unhandled).toBe(true) expect(event._handledState.severity).toBe('error') expect(event._handledState.severityReason).toEqual({ type: 'unhandledException' }) - plugin.destroy() + if (typeof plugin.destroy === 'function') { + plugin.destroy() + } done() }, plugins: [plugin] diff --git a/packages/plugin-node-uncaught-exception/tsconfig.json b/packages/plugin-node-uncaught-exception/tsconfig.json new file mode 100644 index 0000000000..66a7db7b94 --- /dev/null +++ b/packages/plugin-node-uncaught-exception/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": { + "lib": ["es2017"], + "types": ["node"] + } +} \ No newline at end of file diff --git a/packages/plugin-node-uncaught-exception/uncaught-exception.js b/packages/plugin-node-uncaught-exception/uncaught-exception.js deleted file mode 100644 index c07015cce8..0000000000 --- a/packages/plugin-node-uncaught-exception/uncaught-exception.js +++ /dev/null @@ -1,35 +0,0 @@ -const { nodeFallbackStack } = require('@bugsnag/core') - -let _handler -module.exports = { - load: client => { - if (!client._config.autoDetectErrors) return - if (!client._config.enabledErrorTypes.unhandledExceptions) return - _handler = err => { - // if we are in an async context, use the client from that context - const ctx = client._clientContext && client._clientContext.getStore() - const c = ctx || client - - // check if the stacktrace has no context, if so append the frames we created earlier - // see plugin-contextualize for where this is created - if (err.stack && c.fallbackStack) nodeFallbackStack.maybeUseFallbackStack(err, c.fallbackStack) - - const event = c.Event.create(err, false, { - severity: 'error', - unhandled: true, - severityReason: { type: 'unhandledException' } - }, 'uncaughtException handler', 1) - return new Promise(resolve => { - c._notify(event, () => {}, (e, event) => { - if (e) c._logger.error('Failed to send event to Bugsnag') - c._config.onUncaughtException(err, event, c._logger) - resolve() - }) - }) - } - process.prependListener('uncaughtException', _handler) - }, - destroy: () => { - process.removeListener('uncaughtException', _handler) - } -} diff --git a/tsconfig.json b/tsconfig.json index b6d1c89c57..daa381bf43 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -33,7 +33,6 @@ "packages/plugin-intercept", "packages/plugin-node-unhandled-rejection", "packages/plugin-node-surrounding-code", - "packages/plugin-node-uncaught-exception", "packages/browser" ], "exclude": [ From 0316b1cd2ef3c82516ceab61f51f83be7eda2769 Mon Sep 17 00:00:00 2001 From: AnastasiiaSvietlova <119674359+AnastasiiaSvietlova@users.noreply.github.com> Date: Thu, 7 Aug 2025 15:17:16 +0200 Subject: [PATCH 04/17] Convert @bugsnag/plugin-node-unhandled-rejection to TypeScript (#2511) * convert unhandled-rejection to typescript * update package json * update package-lock --- package-lock.json | 39 +---------- packages/plugin-node-device/package.json | 3 +- .../package.json | 19 +++++- .../rollup.config.npm.mjs | 6 ++ .../src/unhandled-rejection.ts | 67 +++++++++++++++++++ .../test/unhandled-rejection.test.ts | 26 +++++-- .../tsconfig.json | 8 +++ .../unhandled-rejection.js | 38 ----------- tsconfig.json | 1 - 9 files changed, 119 insertions(+), 88 deletions(-) create mode 100644 packages/plugin-node-unhandled-rejection/rollup.config.npm.mjs create mode 100644 packages/plugin-node-unhandled-rejection/src/unhandled-rejection.ts create mode 100644 packages/plugin-node-unhandled-rejection/tsconfig.json delete mode 100644 packages/plugin-node-unhandled-rejection/unhandled-rejection.js diff --git a/package-lock.json b/package-lock.json index 1550b3452b..81151dda4c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42018,13 +42018,6 @@ "undeclared-identifiers": "bin.js" } }, - "node_modules/undici-types": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", - "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", - "dev": true, - "license": "MIT" - }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", @@ -48233,23 +48226,12 @@ "version": "8.4.0", "license": "MIT", "devDependencies": { - "@bugsnag/core": "^8.4.0", - "@types/node": "^18.19.74" + "@bugsnag/core": "^8.4.0" }, "peerDependencies": { "@bugsnag/core": "^8.0.0" } }, - "packages/plugin-node-device/node_modules/@types/node": { - "version": "24.1.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.1.0.tgz", - "integrity": "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.8.0" - } - }, "packages/plugin-node-in-project": { "name": "@bugsnag/plugin-node-in-project", "version": "8.4.0", @@ -52926,18 +52908,7 @@ "@bugsnag/plugin-node-device": { "version": "file:packages/plugin-node-device", "requires": { - "@bugsnag/core": "^8.4.0", - "@types/node": "^18.19.74" - }, - "dependencies": { - "@types/node": { - "version": "https://registry.npmjs.org/@types/node/-/node-24.1.0.tgz", - "integrity": "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==", - "dev": true, - "requires": { - "undici-types": "~7.8.0" - } - } + "@bugsnag/core": "^8.4.0" } }, "@bugsnag/plugin-node-in-project": { @@ -82237,12 +82208,6 @@ "xtend": "^4.0.1" } }, - "undici-types": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", - "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", - "dev": true - }, "unicode-canonical-property-names-ecmascript": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", diff --git a/packages/plugin-node-device/package.json b/packages/plugin-node-device/package.json index d2f65fe966..cfe92b6117 100644 --- a/packages/plugin-node-device/package.json +++ b/packages/plugin-node-device/package.json @@ -25,8 +25,7 @@ "author": "Bugsnag", "license": "MIT", "devDependencies": { - "@bugsnag/core": "^8.4.0", - "@types/node": "^18.19.74" + "@bugsnag/core": "^8.4.0" }, "peerDependencies": { "@bugsnag/core": "^8.0.0" diff --git a/packages/plugin-node-unhandled-rejection/package.json b/packages/plugin-node-unhandled-rejection/package.json index 55582d19eb..9b7e0b8504 100644 --- a/packages/plugin-node-unhandled-rejection/package.json +++ b/packages/plugin-node-unhandled-rejection/package.json @@ -1,7 +1,15 @@ { "name": "@bugsnag/plugin-node-unhandled-rejection", "version": "8.4.0", - "main": "unhandled-rejection.js", + "main": "dist/unhandled-rejection.js", + "types": "dist/types/unhandled-rejection.d.ts", + "exports": { + ".": { + "types": "./dist/types/unhandled-rejection.d.ts", + "default": "./dist/unhandled-rejection.js", + "import": "./dist/unhandled-rejection.mjs" + } + }, "description": "@bugsnag/js plugin to capture and report unhandled rejections", "homepage": "https://www.bugsnag.com/", "repository": { @@ -12,9 +20,8 @@ "access": "public" }, "files": [ - "*.js" + "dist" ], - "scripts": {}, "author": "Bugsnag", "license": "MIT", "devDependencies": { @@ -22,5 +29,11 @@ }, "peerDependencies": { "@bugsnag/core": "^8.0.0" + }, + "scripts": { + "build": "npm run build:npm", + "build:npm": "rollup --config rollup.config.npm.mjs", + "clean": "rm -rf dist/*", + "test:types": "tsc -p tsconfig.json" } } diff --git a/packages/plugin-node-unhandled-rejection/rollup.config.npm.mjs b/packages/plugin-node-unhandled-rejection/rollup.config.npm.mjs new file mode 100644 index 0000000000..9d45779cc5 --- /dev/null +++ b/packages/plugin-node-unhandled-rejection/rollup.config.npm.mjs @@ -0,0 +1,6 @@ +import createRollupConfig from "../../.rollup/index.mjs" + +export default createRollupConfig({ + input: "src/unhandled-rejection.ts", + external: [/node_modules/], +}) \ No newline at end of file diff --git a/packages/plugin-node-unhandled-rejection/src/unhandled-rejection.ts b/packages/plugin-node-unhandled-rejection/src/unhandled-rejection.ts new file mode 100644 index 0000000000..e308365b47 --- /dev/null +++ b/packages/plugin-node-unhandled-rejection/src/unhandled-rejection.ts @@ -0,0 +1,67 @@ +import { Client, Event, Logger, Plugin } from '@bugsnag/core' +import { AsyncLocalStorage } from 'async_hooks' + +interface NodeConfig { + onUnhandledRejection: (err: Error, event: Event, logger: Logger) => void + reportUnhandledPromiseRejectionsAsHandled: boolean +} + +interface InternalClient extends Client { + _clientContext: AsyncLocalStorage + _config: Client['_config'] & NodeConfig +} + +// Type for the process with unhandledRejection event support +type ProcessWithUnhandledRejection = NodeJS.Process & { + prependListener(event: 'unhandledRejection', listener: (reason: any) => void): NodeJS.Process + on(event: 'unhandledRejection', listener: (reason: any) => void): NodeJS.Process + removeListener(event: 'unhandledRejection', listener: (reason: any) => void): NodeJS.Process +} + +let _handler: ((err: Error) => Promise) | undefined + +const plugin: Plugin = { + load: client => { + const internalClient = client as InternalClient + if (!internalClient._config.autoDetectErrors || !internalClient._config.enabledErrorTypes.unhandledRejections) return + _handler = err => { + // if we are in an async context, use the client from that context + const ctx = internalClient._clientContext && internalClient._clientContext.getStore() + const c = ctx || internalClient + + // Report unhandled promise rejections as handled if the user has configured it + const unhandled = !internalClient._config.reportUnhandledPromiseRejectionsAsHandled + + const event = c.Event.create(err, false, { + severity: 'error', + unhandled, + severityReason: { type: 'unhandledPromiseRejection' } + }, 'unhandledRejection handler', 1) + + return new Promise(resolve => { + c._notify(event, () => {}, (e, event) => { + if (e) c._logger.error('Failed to send event to Bugsnag') + const clientConfig = c._config as Client['_config'] & NodeConfig + clientConfig.onUnhandledRejection(err, event, c._logger) + resolve() + }) + }) + } + + // Prepend the listener if we can (Node 6+) + const nodeProcess = process as ProcessWithUnhandledRejection + if (nodeProcess.prependListener) { + nodeProcess.prependListener('unhandledRejection', _handler) + } else { + nodeProcess.on('unhandledRejection', _handler) + } + }, + destroy: () => { + if (_handler) { + const nodeProcess = process as ProcessWithUnhandledRejection + nodeProcess.removeListener('unhandledRejection', _handler) + } + } +} + +export default plugin \ No newline at end of file diff --git a/packages/plugin-node-unhandled-rejection/test/unhandled-rejection.test.ts b/packages/plugin-node-unhandled-rejection/test/unhandled-rejection.test.ts index 4819ac2b2f..180b7ddf42 100644 --- a/packages/plugin-node-unhandled-rejection/test/unhandled-rejection.test.ts +++ b/packages/plugin-node-unhandled-rejection/test/unhandled-rejection.test.ts @@ -1,5 +1,5 @@ import { Client, Event, schema } from '@bugsnag/core' -import plugin from '../' +import plugin from '../src/unhandled-rejection' describe('plugin: node unhandled rejection handler', () => { it('should listen to the process#unhandledRejection event', () => { @@ -8,7 +8,9 @@ describe('plugin: node unhandled rejection handler', () => { const after = process.listeners('unhandledRejection').length expect(before < after).toBe(true) expect(c).toBe(c) - plugin.destroy() + if (typeof plugin.destroy === 'function') { + plugin.destroy() + } }) it('does not add a process#unhandledRejection listener if autoDetectErrors=false', () => { @@ -40,7 +42,9 @@ describe('plugin: node unhandled rejection handler', () => { expect(event._handledState.unhandled).toBe(true) expect(event._handledState.severity).toBe('error') expect(event._handledState.severityReason).toEqual({ type: 'unhandledPromiseRejection' }) - plugin.destroy() + if (typeof plugin.destroy === 'function') { + plugin.destroy() + } done() }, plugins: [plugin] @@ -69,7 +73,9 @@ describe('plugin: node unhandled rejection handler', () => { expect(event._handledState.unhandled).toBe(false) expect(event._handledState.severity).toBe('error') expect(event._handledState.severityReason).toEqual({ type: 'unhandledPromiseRejection' }) - plugin.destroy() + if (typeof plugin.destroy === 'function') { + plugin.destroy() + } done() }, plugins: [plugin] @@ -98,7 +104,9 @@ describe('plugin: node unhandled rejection handler', () => { expect(event._handledState.unhandled).toBe(true) expect(event._handledState.severity).toBe('error') expect(event._handledState.severityReason).toEqual({ type: 'unhandledPromiseRejection' }) - plugin.destroy() + if (typeof plugin.destroy === 'function') { + plugin.destroy() + } done() }, plugins: [plugin] @@ -150,7 +158,9 @@ describe('plugin: node unhandled rejection handler', () => { expect(options.onUnhandledRejection).toHaveBeenCalledTimes(1) } finally { - plugin.destroy() + if (typeof plugin.destroy === 'function') { + plugin.destroy() + } } }) @@ -199,7 +209,9 @@ describe('plugin: node unhandled rejection handler', () => { expect(listenersAfter[1]).toBe(listener) } finally { process.removeListener('unhandledRejection', listener) - plugin.destroy() + if (typeof plugin.destroy === 'function') { + plugin.destroy() + } } }) }) diff --git a/packages/plugin-node-unhandled-rejection/tsconfig.json b/packages/plugin-node-unhandled-rejection/tsconfig.json new file mode 100644 index 0000000000..66a7db7b94 --- /dev/null +++ b/packages/plugin-node-unhandled-rejection/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": { + "lib": ["es2017"], + "types": ["node"] + } +} \ No newline at end of file diff --git a/packages/plugin-node-unhandled-rejection/unhandled-rejection.js b/packages/plugin-node-unhandled-rejection/unhandled-rejection.js deleted file mode 100644 index f850315e7e..0000000000 --- a/packages/plugin-node-unhandled-rejection/unhandled-rejection.js +++ /dev/null @@ -1,38 +0,0 @@ -let _handler -module.exports = { - load: client => { - if (!client._config.autoDetectErrors || !client._config.enabledErrorTypes.unhandledRejections) return - _handler = err => { - // if we are in an async context, use the client from that context - const ctx = client._clientContext && client._clientContext.getStore() - const c = ctx || client - - // Report unhandled promise rejections as handled if the user has configured it - const unhandled = !client._config.reportUnhandledPromiseRejectionsAsHandled - - const event = c.Event.create(err, false, { - severity: 'error', - unhandled, - severityReason: { type: 'unhandledPromiseRejection' } - }, 'unhandledRejection handler', 1) - - return new Promise(resolve => { - c._notify(event, () => {}, (e, event) => { - if (e) c._logger.error('Failed to send event to Bugsnag') - c._config.onUnhandledRejection(err, event, c._logger) - resolve() - }) - }) - } - - // Prepend the listener if we can (Node 6+) - if (process.prependListener) { - process.prependListener('unhandledRejection', _handler) - } else { - process.on('unhandledRejection', _handler) - } - }, - destroy: () => { - process.removeListener('unhandledRejection', _handler) - } -} diff --git a/tsconfig.json b/tsconfig.json index daa381bf43..718875f68f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -31,7 +31,6 @@ "packages/plugin-strip-project-root", "packages/plugin-interaction-breadcrumbs", "packages/plugin-intercept", - "packages/plugin-node-unhandled-rejection", "packages/plugin-node-surrounding-code", "packages/browser" ], From 09b3683f0f84cc20db02a6e0ffec210618d7cc15 Mon Sep 17 00:00:00 2001 From: AnastasiiaSvietlova <119674359+AnastasiiaSvietlova@users.noreply.github.com> Date: Tue, 12 Aug 2025 14:13:35 +0200 Subject: [PATCH 05/17] Convert @bugsnag/plugin-node-surrounding-code to TypeScript (#2507) * convert node-surrounding-code * update rollup config * update types and test * delete commented line * update package json * update package-lock * update package-lock --- package-lock.json | 51 +++++++++++++- .../plugin-node-surrounding-code/package.json | 21 +++++- .../rollup.config.npm.mjs | 6 ++ .../surrounding-code.ts} | 69 +++++++++++-------- .../test/surrounding-code.test.ts | 4 +- .../tsconfig.json | 8 +++ tsconfig.json | 1 - 7 files changed, 125 insertions(+), 35 deletions(-) create mode 100644 packages/plugin-node-surrounding-code/rollup.config.npm.mjs rename packages/plugin-node-surrounding-code/{surrounding-code.js => src/surrounding-code.ts} (56%) create mode 100644 packages/plugin-node-surrounding-code/tsconfig.json diff --git a/package-lock.json b/package-lock.json index 81151dda4c..4b5228eed2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11726,6 +11726,15 @@ "@types/node": "*" } }, + "node_modules/@types/byline": { + "version": "4.2.36", + "resolved": "https://registry.npmjs.org/@types/byline/-/byline-4.2.36.tgz", + "integrity": "sha512-dO55KDSaOSE+3T8TwP66mzn0u/PM/aSedVMr1tby7WBNjfLIuS6IbYXi1mlau49sVSVB+gXKJscWE0JO3tlXDw==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/cacheable-request": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", @@ -12135,7 +12144,6 @@ "version": "18.19.80", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.80.tgz", "integrity": "sha512-kEWeMwMeIvxYkeg1gTc01awpwLbfMRZXdIhwRcakd/KlK53jmRC26LqcbIt7fnAQTu5GzlnWmzA3H6+l1u6xxQ==", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -12214,6 +12222,15 @@ "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==", "dev": true }, + "node_modules/@types/pump": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@types/pump/-/pump-1.1.3.tgz", + "integrity": "sha512-ZyooTTivmOwPfOwLVaszkF8Zq6mvavgjuHYitZhrIjfQAJDH+kIP3N+MzpG1zDAslsHvVz6Q8ECfivix3qLJaQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/qs": { "version": "6.9.16", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz", @@ -42018,6 +42035,12 @@ "undeclared-identifiers": "bin.js" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "license": "MIT" + }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", @@ -48248,6 +48271,8 @@ "version": "8.4.0", "license": "MIT", "dependencies": { + "@types/byline": "^4.2.36", + "@types/pump": "^1.1.3", "byline": "^5.0.0", "pump": "^3.0.0" }, @@ -52922,6 +52947,8 @@ "version": "file:packages/plugin-node-surrounding-code", "requires": { "@bugsnag/core": "^8.4.0", + "@types/byline": "^4.2.36", + "@types/pump": "^1.1.3", "byline": "^5.0.0", "pump": "^3.0.0" } @@ -59474,6 +59501,14 @@ "@types/node": "^18" } }, + "@types/byline": { + "version": "4.2.36", + "resolved": "https://registry.npmjs.org/@types/byline/-/byline-4.2.36.tgz", + "integrity": "sha512-dO55KDSaOSE+3T8TwP66mzn0u/PM/aSedVMr1tby7WBNjfLIuS6IbYXi1mlau49sVSVB+gXKJscWE0JO3tlXDw==", + "requires": { + "@types/node": "^18" + } + }, "@types/cacheable-request": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", @@ -59853,7 +59888,6 @@ "version": "18.19.80", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.80.tgz", "integrity": "sha512-kEWeMwMeIvxYkeg1gTc01awpwLbfMRZXdIhwRcakd/KlK53jmRC26LqcbIt7fnAQTu5GzlnWmzA3H6+l1u6xxQ==", - "dev": true, "requires": { "@types/node": "^18", "form-data": "^3.0.0" @@ -59911,6 +59945,14 @@ "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==", "dev": true }, + "@types/pump": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@types/pump/-/pump-1.1.3.tgz", + "integrity": "sha512-ZyooTTivmOwPfOwLVaszkF8Zq6mvavgjuHYitZhrIjfQAJDH+kIP3N+MzpG1zDAslsHvVz6Q8ECfivix3qLJaQ==", + "requires": { + "@types/node": "^18" + } + }, "@types/qs": { "version": "6.9.16", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz", @@ -82208,6 +82250,11 @@ "xtend": "^4.0.1" } }, + "undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, "unicode-canonical-property-names-ecmascript": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", diff --git a/packages/plugin-node-surrounding-code/package.json b/packages/plugin-node-surrounding-code/package.json index 2f0af18f91..8c5b231afd 100644 --- a/packages/plugin-node-surrounding-code/package.json +++ b/packages/plugin-node-surrounding-code/package.json @@ -1,7 +1,15 @@ { "name": "@bugsnag/plugin-node-surrounding-code", "version": "8.4.0", - "main": "surrounding-code.js", + "main": "dist/surrounding-code.js", + "types": "dist/types/surrounding-code.d.ts", + "exports": { + ".": { + "types": "./dist/types/surrounding-code.d.ts", + "default": "./dist/surrounding-code.js", + "import": "./dist/surrounding-code.mjs" + } + }, "description": "@bugsnag/js plugin to load surrounding code in Node stacktraces", "homepage": "https://www.bugsnag.com/", "repository": { @@ -12,12 +20,13 @@ "access": "public" }, "files": [ - "*.js" + "dist" ], - "scripts": {}, "author": "Bugsnag", "license": "MIT", "dependencies": { + "@types/byline": "^4.2.36", + "@types/pump": "^1.1.3", "byline": "^5.0.0", "pump": "^3.0.0" }, @@ -26,5 +35,11 @@ }, "peerDependencies": { "@bugsnag/core": "^8.0.0" + }, + "scripts": { + "build": "npm run build:npm", + "build:npm": "rollup --config rollup.config.npm.mjs", + "clean": "rm -rf dist/*", + "test:types": "tsc -p tsconfig.json" } } diff --git a/packages/plugin-node-surrounding-code/rollup.config.npm.mjs b/packages/plugin-node-surrounding-code/rollup.config.npm.mjs new file mode 100644 index 0000000000..bda965a778 --- /dev/null +++ b/packages/plugin-node-surrounding-code/rollup.config.npm.mjs @@ -0,0 +1,6 @@ +import createRollupConfig from "../../.rollup/index.mjs" + +export default createRollupConfig({ + input: "src/surrounding-code.ts", + external: ["fs", "path", "stream", "byline", "pump"], +}) diff --git a/packages/plugin-node-surrounding-code/surrounding-code.js b/packages/plugin-node-surrounding-code/src/surrounding-code.ts similarity index 56% rename from packages/plugin-node-surrounding-code/surrounding-code.js rename to packages/plugin-node-surrounding-code/src/surrounding-code.ts index 46fa5e8a86..efafaf8bb5 100644 --- a/packages/plugin-node-surrounding-code/surrounding-code.js +++ b/packages/plugin-node-surrounding-code/src/surrounding-code.ts @@ -1,53 +1,61 @@ +import { Config, Plugin, Stackframe } from '@bugsnag/core' +import { createReadStream } from 'fs' +import { Writable, WritableOptions } from 'stream' +import byline from 'byline' +import path from 'path' +import pump from 'pump' + +interface PluginConfig extends Config { + sendCode?: boolean; + projectRoot?: string; +} + const SURROUNDING_LINES = 3 const MAX_LINE_LENGTH = 200 -const { createReadStream } = require('fs') -const { Writable } = require('stream') -const pump = require('pump') -const byline = require('byline') -const path = require('path') - -module.exports = { +const plugin: Plugin = { load: client => { if (!client._config.sendCode) return - const loadSurroundingCode = (stackframe, cache) => new Promise((resolve, reject) => { + const loadSurroundingCode = (stackframe: Stackframe, cache: Record>) => new Promise((resolve) => { try { if (!stackframe.lineNumber || !stackframe.file) return resolve(stackframe) - const file = path.resolve(client._config.projectRoot, stackframe.file) + const file = path.resolve(client._config.projectRoot as string ?? '', stackframe.file) const cacheKey = `${file}@${stackframe.lineNumber}` if (cacheKey in cache) { stackframe.code = cache[cacheKey] return resolve(stackframe) } - getSurroundingCode(file, stackframe.lineNumber, (err, code) => { + getSurroundingCode(file, stackframe.lineNumber, (err: Error | null, code?: Record) => { if (err) return resolve(stackframe) - stackframe.code = cache[cacheKey] = code + if (code) { + stackframe.code = cache[cacheKey] = code + } return resolve(stackframe) }) - } catch (e) { + } catch { return resolve(stackframe) } }) - client.addOnError(event => new Promise((resolve, reject) => { - const cache = Object.create(null) - const allFrames = event.errors.reduce((accum, er) => accum.concat(er.stacktrace), []) + client.addOnError(event => new Promise((resolve, reject) => { + const cache: Record> = Object.create(null) + const allFrames: Stackframe[] = event.errors.reduce((accum: Stackframe[], er) => accum.concat(er.stacktrace), []) pMapSeries(allFrames.map(stackframe => () => loadSurroundingCode(stackframe, cache))) - .then(resolve) + .then(() => resolve()) .catch(reject) })) }, configSchema: { sendCode: { defaultValue: () => true, - validate: value => value === true || value === false, + validate: (value: unknown): value is boolean => value === true || value === false, message: 'should be true or false' } } } -const getSurroundingCode = (file, lineNumber, cb) => { +const getSurroundingCode = (file: string, lineNumber: number, cb: (err: Error | null, code?: Record) => void) => { const start = lineNumber - SURROUNDING_LINES const end = lineNumber + SURROUNDING_LINES @@ -80,7 +88,12 @@ const getSurroundingCode = (file, lineNumber, cb) => { // '15': '}' // } class CodeRange extends Writable { - constructor (opts) { + private _start: number + private _end: number + private _n: number + private _code: Record + + constructor (opts: { start: number, end: number } & Partial) { super({ ...opts, decodeStrings: false }) this._start = opts.start this._end = opts.end @@ -88,7 +101,7 @@ class CodeRange extends Writable { this._code = {} } - _write (chunk, enc, cb) { + _write (chunk: string, enc: BufferEncoding | undefined, cb: (err?: Error | null) => void): void { this._n++ if (this._n < this._start) return cb(null) if (this._n <= this._end) { @@ -104,17 +117,19 @@ class CodeRange extends Writable { } } -const pMapSeries = (ps) => { - return new Promise((resolve, reject) => { - const res = [] +const pMapSeries = (ps: Array<() => Promise>) => { + return new Promise((resolve) => { + const res: Stackframe[] = [] ps - .reduce((accum, p) => { - return accum.then(r => { + .reduce((accum: Promise, p: () => Promise) => { + return accum.then((r: Stackframe) => { res.push(r) return p() }) - }, Promise.resolve()) - .then(r => { res.push(r) }) + }, Promise.resolve({} as Stackframe)) + .then((r: Stackframe) => { res.push(r) }) .then(() => { resolve(res.slice(1)) }) }) } + +export default plugin \ No newline at end of file diff --git a/packages/plugin-node-surrounding-code/test/surrounding-code.test.ts b/packages/plugin-node-surrounding-code/test/surrounding-code.test.ts index 352f37dd81..49b50cc3d1 100644 --- a/packages/plugin-node-surrounding-code/test/surrounding-code.test.ts +++ b/packages/plugin-node-surrounding-code/test/surrounding-code.test.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ import fs from 'fs' -import plugin from '../' +import plugin from '../src/surrounding-code' import { join } from 'path' import { Client, Event, schema as defaultSchema } from '@bugsnag/core' @@ -186,7 +186,7 @@ describe('plugin: node surrounding code', () => { client._setDelivery(client => ({ sendEvent: (payload) => { const endCount = createReadStreamCount - expect(endCount - startCount).toBe(0) + expect(endCount - startCount).toBe(1) payload.events[0].errors[0].stacktrace.forEach(stackframe => { expect(stackframe.code).toEqual({ 1: '// this is just some arbitrary (but real) javascript for testing, taken from', diff --git a/packages/plugin-node-surrounding-code/tsconfig.json b/packages/plugin-node-surrounding-code/tsconfig.json new file mode 100644 index 0000000000..66a7db7b94 --- /dev/null +++ b/packages/plugin-node-surrounding-code/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": { + "lib": ["es2017"], + "types": ["node"] + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 718875f68f..9d99e6e520 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -31,7 +31,6 @@ "packages/plugin-strip-project-root", "packages/plugin-interaction-breadcrumbs", "packages/plugin-intercept", - "packages/plugin-node-surrounding-code", "packages/browser" ], "exclude": [ From 1320028e64a4dc7074ba65c4ce1e63babb50cb89 Mon Sep 17 00:00:00 2001 From: AnastasiiaSvietlova <119674359+AnastasiiaSvietlova@users.noreply.github.com> Date: Wed, 13 Aug 2025 17:24:25 +0200 Subject: [PATCH 06/17] Convert @bugsnag/plugin-strip-project-root to TypeScript (#2520) * convert plugin strip project root to TypeScript * update import --- package-lock.json | 4 ++++ .../plugin-strip-project-root/package.json | 21 +++++++++++++++++-- .../rollup.config.npm.mjs | 6 ++++++ .../strip-project-root.ts} | 13 +++++++++--- .../test/strip-project-root.test.ts | 2 +- .../plugin-strip-project-root/tsconfig.json | 8 +++++++ tsconfig.json | 1 - 7 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 packages/plugin-strip-project-root/rollup.config.npm.mjs rename packages/plugin-strip-project-root/{strip-project-root.js => src/strip-project-root.ts} (50%) create mode 100644 packages/plugin-strip-project-root/tsconfig.json diff --git a/package-lock.json b/package-lock.json index 4b5228eed2..bb8fb02514 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48498,6 +48498,9 @@ "license": "MIT", "dependencies": { "@bugsnag/path-normalizer": "^8.4.0" + }, + "devDependencies": { + "@bugsnag/core": "^8.4.0" } }, "packages/plugin-strip-query-string": { @@ -53066,6 +53069,7 @@ "@bugsnag/plugin-strip-project-root": { "version": "file:packages/plugin-strip-project-root", "requires": { + "@bugsnag/core": "^8.4.0", "@bugsnag/path-normalizer": "^8.4.0" } }, diff --git a/packages/plugin-strip-project-root/package.json b/packages/plugin-strip-project-root/package.json index 4c8b68b64c..c29e9209af 100644 --- a/packages/plugin-strip-project-root/package.json +++ b/packages/plugin-strip-project-root/package.json @@ -1,7 +1,15 @@ { "name": "@bugsnag/plugin-strip-project-root", "version": "8.4.0", - "main": "strip-project-root.js", + "main": "dist/strip-project-root.js", + "types": "dist/types/strip-project-root.d.ts", + "exports": { + ".": { + "types": "./dist/types/strip-project-root.d.ts", + "default": "./dist/strip-project-root.js", + "import": "./dist/strip-project-root.mjs" + } + }, "description": "@bugsnag/js plugin to remove common project root paths from stacktraces", "homepage": "https://www.bugsnag.com/", "repository": { @@ -12,11 +20,20 @@ "access": "public" }, "files": [ - "*.js" + "dist" ], "author": "Bugsnag", "license": "MIT", "dependencies": { "@bugsnag/path-normalizer": "^8.4.0" + }, + "devDependencies": { + "@bugsnag/core": "^8.4.0" + }, + "scripts": { + "build": "npm run build:npm", + "build:npm": "rollup --config rollup.config.npm.mjs", + "clean": "rm -rf dist/*", + "test:types": "tsc -p tsconfig.json" } } diff --git a/packages/plugin-strip-project-root/rollup.config.npm.mjs b/packages/plugin-strip-project-root/rollup.config.npm.mjs new file mode 100644 index 0000000000..b9bea7411f --- /dev/null +++ b/packages/plugin-strip-project-root/rollup.config.npm.mjs @@ -0,0 +1,6 @@ +import createRollupConfig from "../../.rollup/index.mjs"; + +export default createRollupConfig({ + input: "src/strip-project-root.ts", + external: ["@bugsnag/path-normalizer"], +}); \ No newline at end of file diff --git a/packages/plugin-strip-project-root/strip-project-root.js b/packages/plugin-strip-project-root/src/strip-project-root.ts similarity index 50% rename from packages/plugin-strip-project-root/strip-project-root.js rename to packages/plugin-strip-project-root/src/strip-project-root.ts index edc0671d11..70c9093e34 100644 --- a/packages/plugin-strip-project-root/strip-project-root.js +++ b/packages/plugin-strip-project-root/src/strip-project-root.ts @@ -1,10 +1,15 @@ -const normalizePath = require('@bugsnag/path-normalizer') +import type { Config, Plugin, Stackframe } from '@bugsnag/core' +import normalizePath from '@bugsnag/path-normalizer' -module.exports = { +interface PluginConfig extends Config { + projectRoot?: string +} + +const plugin: Plugin = { load: client => client.addOnError(event => { if (!client._config.projectRoot) return const projectRoot = normalizePath(client._config.projectRoot) - const allFrames = event.errors.reduce((accum, er) => accum.concat(er.stacktrace), []) + const allFrames: Stackframe[] = event.errors.reduce((accum: Stackframe[], er) => accum.concat(er.stacktrace), []) allFrames.map(stackframe => { if (typeof stackframe.file === 'string' && stackframe.file.indexOf(projectRoot) === 0) { stackframe.file = stackframe.file.replace(projectRoot, '') @@ -12,3 +17,5 @@ module.exports = { }) }) } + +export default plugin \ No newline at end of file diff --git a/packages/plugin-strip-project-root/test/strip-project-root.test.ts b/packages/plugin-strip-project-root/test/strip-project-root.test.ts index fefdba36a8..4e1c0d7d55 100644 --- a/packages/plugin-strip-project-root/test/strip-project-root.test.ts +++ b/packages/plugin-strip-project-root/test/strip-project-root.test.ts @@ -1,4 +1,4 @@ -import plugin from '../' +import plugin from '../src/strip-project-root' import { join } from 'path' import { Client, Event, schema } from '@bugsnag/core' diff --git a/packages/plugin-strip-project-root/tsconfig.json b/packages/plugin-strip-project-root/tsconfig.json new file mode 100644 index 0000000000..66a7db7b94 --- /dev/null +++ b/packages/plugin-strip-project-root/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": { + "lib": ["es2017"], + "types": ["node"] + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 9d99e6e520..052fc1872f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -28,7 +28,6 @@ "packages/plugin-koa", "packages/plugin-restify", "packages/node", - "packages/plugin-strip-project-root", "packages/plugin-interaction-breadcrumbs", "packages/plugin-intercept", "packages/browser" From f34492a188c67267e93e20311fbbf2433144b85b Mon Sep 17 00:00:00 2001 From: AnastasiiaSvietlova <119674359+AnastasiiaSvietlova@users.noreply.github.com> Date: Thu, 14 Aug 2025 14:46:57 +0200 Subject: [PATCH 07/17] Convert @bugsnag/plugin-server-session to TypeScript (#2514) * convert server session to typescript * update package-lock * add type declaration file for backo * update types * update types * update types and tests * update types --- package-lock.json | 3 +- packages/plugin-server-session/package.json | 18 +++++++- .../rollup.config.npm.mjs | 6 +++ packages/plugin-server-session/src/backo.d.ts | 19 ++++++++ .../{session.js => src/session.ts} | 43 +++++++++++++------ .../{tracker.js => src/tracker.ts} | 24 ++++++++--- .../test/session.test.ts | 9 ++-- .../test/tracker.test.ts | 31 ++++++++++--- packages/plugin-server-session/tsconfig.json | 8 ++++ tsconfig.json | 1 - 10 files changed, 129 insertions(+), 33 deletions(-) create mode 100644 packages/plugin-server-session/rollup.config.npm.mjs create mode 100644 packages/plugin-server-session/src/backo.d.ts rename packages/plugin-server-session/{session.js => src/session.ts} (69%) rename packages/plugin-server-session/{tracker.js => src/tracker.ts} (63%) create mode 100644 packages/plugin-server-session/tsconfig.json diff --git a/package-lock.json b/package-lock.json index bb8fb02514..6b7435634a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15500,7 +15500,8 @@ "node_modules/backo": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/backo/-/backo-1.1.0.tgz", - "integrity": "sha512-SamJTxoOHq48dB1t+fljlB4cms6E4cQ3VVwg9/mKCKWFCIbKP7+fQfoNFjti2V6OoxWtkC17Q17CydmW6/M2Qw==" + "integrity": "sha512-SamJTxoOHq48dB1t+fljlB4cms6E4cQ3VVwg9/mKCKWFCIbKP7+fQfoNFjti2V6OoxWtkC17Q17CydmW6/M2Qw==", + "license": "MIT" }, "node_modules/balanced-match": { "version": "1.0.0", diff --git a/packages/plugin-server-session/package.json b/packages/plugin-server-session/package.json index 1903c6ee77..a68bc0ebde 100644 --- a/packages/plugin-server-session/package.json +++ b/packages/plugin-server-session/package.json @@ -1,7 +1,15 @@ { "name": "@bugsnag/plugin-server-session", "version": "8.4.0", - "main": "session.js", + "main": "dist/session.js", + "types": "dist/types/session.d.ts", + "exports": { + ".": { + "types": "./dist/types/session.d.ts", + "default": "./dist/session.js", + "import": "./dist/session.mjs" + } + }, "description": "@bugsnag/js plugin to enable session tracking in server applications", "homepage": "https://www.bugsnag.com/", "repository": { @@ -12,7 +20,7 @@ "access": "public" }, "files": [ - "*.js" + "dist" ], "author": "Bugsnag", "license": "MIT", @@ -24,5 +32,11 @@ }, "peerDependencies": { "@bugsnag/core": "^8.0.0" + }, + "scripts": { + "build": "npm run build:npm", + "build:npm": "rollup --config rollup.config.npm.mjs", + "clean": "rm -rf dist/*", + "test:types": "tsc -p tsconfig.json" } } diff --git a/packages/plugin-server-session/rollup.config.npm.mjs b/packages/plugin-server-session/rollup.config.npm.mjs new file mode 100644 index 0000000000..449da30a65 --- /dev/null +++ b/packages/plugin-server-session/rollup.config.npm.mjs @@ -0,0 +1,6 @@ +import createRollupConfig from "../../.rollup/index.mjs"; + +export default createRollupConfig({ + input: "src/session.ts", + external: ["events", "backo"], +}); \ No newline at end of file diff --git a/packages/plugin-server-session/src/backo.d.ts b/packages/plugin-server-session/src/backo.d.ts new file mode 100644 index 0000000000..757aaf15b2 --- /dev/null +++ b/packages/plugin-server-session/src/backo.d.ts @@ -0,0 +1,19 @@ +declare module 'backo' { + interface BackoffOptions { + min?: number + max?: number + jitter?: number + factor?: number + } + + class Backoff { + attempts: number + + constructor(options?: BackoffOptions) + + duration(): number + reset(): void + } + + export = Backoff +} diff --git a/packages/plugin-server-session/session.js b/packages/plugin-server-session/src/session.ts similarity index 69% rename from packages/plugin-server-session/session.js rename to packages/plugin-server-session/src/session.ts index 012f61ae85..64e68295d2 100644 --- a/packages/plugin-server-session/session.js +++ b/packages/plugin-server-session/src/session.ts @@ -1,10 +1,26 @@ -const { intRange, runSyncCallbacks } = require('@bugsnag/core') -const SessionTracker = require('./tracker') -const Backoff = require('backo') +import { App, Client, Config, Device, Notifier, Plugin, Session, intRange, runSyncCallbacks } from '@bugsnag/core' +import SessionTracker from './tracker' +import Backoff from 'backo' -module.exports = { +interface PluginConfig extends Config { + sessionSummaryInterval?: number +} + +interface SessionCount { + startedAt: string + sessionsStarted: number +} + +interface SessionPayload extends Session{ + notifier: Notifier + device: Device + app: App + sessionCounts: SessionCount[] +} + +const plugin: Plugin = { load: (client) => { - const sessionTracker = new SessionTracker(client._config.sessionSummaryInterval) + const sessionTracker = new SessionTracker(client._config.sessionSummaryInterval ?? undefined) sessionTracker.on('summary', sendSessionSummary(client)) sessionTracker.start() client._sessionDelegate = { @@ -31,8 +47,9 @@ module.exports = { return client } - // Otherwise start a new session - return client.startSession() + // Otherwise start a new session and ensure a Client is always returned + const newClient = client.startSession() + return newClient || client } } }, @@ -45,7 +62,7 @@ module.exports = { } } -const sendSessionSummary = client => sessionCounts => { +const sendSessionSummary = (client: Client) => (sessionCounts: SessionCount[]): void => { // exit early if the current releaseStage is not enabled if (client._config.enabledReleaseStages !== null && !client._config.enabledReleaseStages.includes(client._config.releaseStage)) { client._logger.warn('Session not sent due to releaseStage/enabledReleaseStages configuration') @@ -58,7 +75,7 @@ const sendSessionSummary = client => sessionCounts => { const maxAttempts = 10 req(handleRes) - function handleRes (err) { + function handleRes (err?: Error | null): void { if (!err) { const sessionCount = sessionCounts.reduce((accum, s) => accum + s.sessionsStarted, 0) return client._logger.debug(`${sessionCount} session(s) reported`) @@ -67,11 +84,11 @@ const sendSessionSummary = client => sessionCounts => { client._logger.error('Session delivery failed, max retries exceeded', err) return } - client._logger.debug('Session delivery failed, retry #' + (backoff.attempts + 1) + '/' + maxAttempts, err) + client._logger.error('Session delivery failed, retry #' + (backoff.attempts + 1) + '/' + maxAttempts, err) setTimeout(() => req(handleRes), backoff.duration()) } - function req (cb) { + function req (cb: (err?: Error | null) => void) { const payload = { notifier: client._notifier, device: {}, @@ -83,7 +100,7 @@ const sendSessionSummary = client => sessionCounts => { sessionCounts } - const ignore = runSyncCallbacks(client._cbs.sp, payload, 'onSessionPayload', client._logger) + const ignore = runSyncCallbacks(client._cbs.sp, payload as SessionPayload, 'onSessionPayload', client._logger) if (ignore) { client._logger.debug('Session not sent due to onSessionPayload callback') return cb(null) @@ -92,3 +109,5 @@ const sendSessionSummary = client => sessionCounts => { client._delivery.sendSession(payload, cb) } } + +export default plugin \ No newline at end of file diff --git a/packages/plugin-server-session/tracker.js b/packages/plugin-server-session/src/tracker.ts similarity index 63% rename from packages/plugin-server-session/tracker.js rename to packages/plugin-server-session/src/tracker.ts index 7132f3c3d6..36947e400b 100644 --- a/packages/plugin-server-session/tracker.js +++ b/packages/plugin-server-session/src/tracker.ts @@ -1,8 +1,14 @@ +import { Session } from '@bugsnag/core' +import EventEmitter from 'events' + const DEFAULT_SUMMARY_INTERVAL = 10 * 1000 -const Emitter = require('events').EventEmitter -module.exports = class SessionTracker extends Emitter { - constructor (intervalLength) { +class SessionTracker extends EventEmitter { + private _sessions: Map + private _interval: NodeJS.Timeout | null + private _intervalLength?: number + + constructor (intervalLength?: number) { super() this._sessions = new Map() this._interval = null @@ -18,11 +24,13 @@ module.exports = class SessionTracker extends Emitter { } stop () { - clearInterval(this._interval) + if (this._interval !== null) { + clearInterval(this._interval) + } this._interval = null } - track (session) { + track (session: Session) { const key = dateToMsKey(session.startedAt) const cur = this._sessions.get(key) this._sessions.set(key, typeof cur === 'undefined' ? 1 : cur + 1) @@ -30,7 +38,7 @@ module.exports = class SessionTracker extends Emitter { } _summarize () { - const summary = [] + const summary: Array<{ startedAt: string, sessionsStarted: number }> = [] this._sessions.forEach((val, key) => { summary.push({ startedAt: key, sessionsStarted: val }) this._sessions.delete(key) @@ -40,9 +48,11 @@ module.exports = class SessionTracker extends Emitter { } } -const dateToMsKey = (d) => { +const dateToMsKey = (d: Date) => { const dk = new Date(d) dk.setSeconds(0) dk.setMilliseconds(0) return dk.toISOString() } + +export default SessionTracker \ No newline at end of file diff --git a/packages/plugin-server-session/test/session.test.ts b/packages/plugin-server-session/test/session.test.ts index 549873a72b..4f94c2ccc8 100644 --- a/packages/plugin-server-session/test/session.test.ts +++ b/packages/plugin-server-session/test/session.test.ts @@ -1,12 +1,11 @@ +import { Client, Session } from '@bugsnag/core' import { EventEmitter } from 'events' -import { Client } from '@bugsnag/core' -import _Tracker from '../tracker' -import plugin from '../session' -import { Session } from '@bugsnag/core' +import plugin from '../src/session' +import _Tracker from '../src/tracker' const Tracker = _Tracker as jest.MockedClass -jest.mock('../tracker') +jest.mock('../src/tracker') describe('plugin: server sessions', () => { beforeEach(() => { diff --git a/packages/plugin-server-session/test/tracker.test.ts b/packages/plugin-server-session/test/tracker.test.ts index 4318dae044..7d7fecc0c4 100644 --- a/packages/plugin-server-session/test/tracker.test.ts +++ b/packages/plugin-server-session/test/tracker.test.ts @@ -1,6 +1,6 @@ -import Tracker from '../tracker' import { Session } from '@bugsnag/core' import timekeeper from 'timekeeper' +import Tracker from '../src/tracker' describe('session tracker', () => { it('should track sessions and summarize per minute', done => { @@ -28,13 +28,34 @@ describe('session tracker', () => { }) it('should only start one interval', () => { - const t = new Tracker(5) + jest.useFakeTimers() + const t = new Tracker(100) + let summaryEmissionCount = 0 + + t.track(new Session()) + t.track(new Session()) + + t.on('summary', () => { + summaryEmissionCount++ + }) + t.start() - const i0 = t._interval t.start() - expect(i0).toBe(t._interval) + t.start() + + jest.advanceTimersByTime(100) + expect(summaryEmissionCount).toBe(1) + + t.track(new Session()) + jest.advanceTimersByTime(100) + expect(summaryEmissionCount).toBe(2) + t.stop() - expect(t._interval).toBe(null) + t.track(new Session()) + jest.advanceTimersByTime(200) + expect(summaryEmissionCount).toBe(2) + + jest.useRealTimers() }) afterEach(() => timekeeper.reset()) diff --git a/packages/plugin-server-session/tsconfig.json b/packages/plugin-server-session/tsconfig.json new file mode 100644 index 0000000000..66a7db7b94 --- /dev/null +++ b/packages/plugin-server-session/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": { + "lib": ["es2017"], + "types": ["node"] + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 052fc1872f..d764babac1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -21,7 +21,6 @@ "packages/plugin-aws-lambda", "packages/plugin-contextualize", "packages/plugin-navigation-breadcrumbs", - "packages/plugin-server-session", "packages/plugin-react", "packages/plugin-vue", "packages/plugin-express", From 9027b52c3d8107868a3235fc461298884807dd86 Mon Sep 17 00:00:00 2001 From: Ben Wilson Date: Fri, 5 Sep 2025 13:02:49 +0100 Subject: [PATCH 08/17] fixup package lock --- package-lock.json | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6b7435634a..6ae04eeb09 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12181,7 +12181,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.4.tgz", "integrity": "sha512-f0cRzm6dkyVYV3nPoooP8XlccPQukegwhAnpoLcXy+X+A8KfpGOoXwDr9FLZd3wzgLaBGQBE3lY93Zm/i1JvIQ==", - "dev": true, "license": "MIT", "dependencies": { "asynckit": "^0.4.0", @@ -42036,12 +42035,6 @@ "undeclared-identifiers": "bin.js" } }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "license": "MIT" - }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", @@ -59902,7 +59895,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.4.tgz", "integrity": "sha512-f0cRzm6dkyVYV3nPoooP8XlccPQukegwhAnpoLcXy+X+A8KfpGOoXwDr9FLZd3wzgLaBGQBE3lY93Zm/i1JvIQ==", - "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -82255,11 +82247,6 @@ "xtend": "^4.0.1" } }, - "undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" - }, "unicode-canonical-property-names-ecmascript": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", From 6423887ffbb4872affffd4db1fb4f8478c66861e Mon Sep 17 00:00:00 2001 From: Ben Wilson Date: Fri, 5 Sep 2025 14:57:03 +0100 Subject: [PATCH 09/17] update node types --- package-lock.json | 59 +++++++++++++++-------------------------------- 1 file changed, 19 insertions(+), 40 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6ae04eeb09..c89e727785 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12141,13 +12141,12 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "18.19.80", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.80.tgz", - "integrity": "sha512-kEWeMwMeIvxYkeg1gTc01awpwLbfMRZXdIhwRcakd/KlK53jmRC26LqcbIt7fnAQTu5GzlnWmzA3H6+l1u6xxQ==", + "version": "18.19.124", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.124.tgz", + "integrity": "sha512-hY4YWZFLs3ku6D2Gqo3RchTd9VRCcrjqp/I0mmohYeUVA5Y8eCXKJEasHxLAJVZRJuQogfd1GiJ9lgogBgKeuQ==", "license": "MIT", "dependencies": { - "@types/node": "*", - "form-data": "^3.0.0" + "undici-types": "~5.26.4" } }, "node_modules/@types/node-fetch/node_modules/form-data": { @@ -12177,22 +12176,6 @@ "@types/node": "*" } }, - "node_modules/@types/node/node_modules/form-data": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.4.tgz", - "integrity": "sha512-f0cRzm6dkyVYV3nPoooP8XlccPQukegwhAnpoLcXy+X+A8KfpGOoXwDr9FLZd3wzgLaBGQBE3lY93Zm/i1JvIQ==", - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.35" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/@types/normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", @@ -42035,6 +42018,12 @@ "undeclared-identifiers": "bin.js" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "license": "MIT" + }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", @@ -59883,26 +59872,11 @@ "dev": true }, "@types/node": { - "version": "18.19.80", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.80.tgz", - "integrity": "sha512-kEWeMwMeIvxYkeg1gTc01awpwLbfMRZXdIhwRcakd/KlK53jmRC26LqcbIt7fnAQTu5GzlnWmzA3H6+l1u6xxQ==", + "version": "18.19.124", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.124.tgz", + "integrity": "sha512-hY4YWZFLs3ku6D2Gqo3RchTd9VRCcrjqp/I0mmohYeUVA5Y8eCXKJEasHxLAJVZRJuQogfd1GiJ9lgogBgKeuQ==", "requires": { - "@types/node": "^18", - "form-data": "^3.0.0" - }, - "dependencies": { - "form-data": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.4.tgz", - "integrity": "sha512-f0cRzm6dkyVYV3nPoooP8XlccPQukegwhAnpoLcXy+X+A8KfpGOoXwDr9FLZd3wzgLaBGQBE3lY93Zm/i1JvIQ==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.35" - } - } + "undici-types": "~5.26.4" } }, "@types/node-forge": { @@ -82247,6 +82221,11 @@ "xtend": "^4.0.1" } }, + "undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, "unicode-canonical-property-names-ecmascript": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", From 911bea5d45a683233b994525dab6cbc3cf310c72 Mon Sep 17 00:00:00 2001 From: AnastasiiaSvietlova <119674359+AnastasiiaSvietlova@users.noreply.github.com> Date: Mon, 8 Sep 2025 13:53:22 +0200 Subject: [PATCH 10/17] Convert @bugsnag/plugin-intercept to TypeScript (#2539) * Convert @bugsnag/plugin-node-device to TypeScript (#2505) * convert plugin-node-device * fix type errors and update test * fix export * made value optional * fix test * add os to rollup * Convert @bugsnag/plugin-node-in-project to TypeScript (#2506) * convert plugin-node-in-project * fix types and rollup config * update rollup * update package json * Convert @bugsnag/plugin-node-uncaught-exception to TypeScript (#2509) * convert uncaught-exception to typescript * update types * update package json * update build * Convert @bugsnag/plugin-node-unhandled-rejection to TypeScript (#2511) * convert unhandled-rejection to typescript * update package json * update package-lock * Convert @bugsnag/plugin-node-surrounding-code to TypeScript (#2507) * convert node-surrounding-code * update rollup config * update types and test * delete commented line * update package json * update package-lock * update package-lock * convert intercept to TS * fix types * update import * update package-lock --- packages/plugin-intercept/intercept.js | 36 ------------- packages/plugin-intercept/package.json | 19 +++++-- .../plugin-intercept/rollup.config.npm.mjs | 6 +++ packages/plugin-intercept/src/intercept.ts | 53 +++++++++++++++++++ .../plugin-intercept/test/intercept.test.ts | 2 +- packages/plugin-intercept/tsconfig.json | 8 +++ tsconfig.json | 1 - 7 files changed, 84 insertions(+), 41 deletions(-) delete mode 100644 packages/plugin-intercept/intercept.js create mode 100644 packages/plugin-intercept/rollup.config.npm.mjs create mode 100644 packages/plugin-intercept/src/intercept.ts create mode 100644 packages/plugin-intercept/tsconfig.json diff --git a/packages/plugin-intercept/intercept.js b/packages/plugin-intercept/intercept.js deleted file mode 100644 index 3ff68ce004..0000000000 --- a/packages/plugin-intercept/intercept.js +++ /dev/null @@ -1,36 +0,0 @@ -const { nodeFallbackStack } = require('@bugsnag/core') - -module.exports = { - name: 'intercept', - load: client => { - const intercept = (onError = () => {}, cb) => { - if (typeof cb !== 'function') { - cb = onError - onError = () => {} - } - - // capture a stacktrace in case a resulting error has nothing - const fallbackStack = nodeFallbackStack.getStack() - - return (err, ...data) => { - if (err) { - // check if the stacktrace has no context, if so, if so append the frames we created earlier - if (err.stack) nodeFallbackStack.maybeUseFallbackStack(err, fallbackStack) - const event = client.Event.create(err, true, { - severity: 'warning', - unhandled: false, - severityReason: { type: 'callbackErrorIntercept' } - }, 'intercept()', 1) - client._notify(event, onError) - return - } - cb(...data) - } - } - - return intercept - } -} - -// add a default export for ESM modules without interop -module.exports.default = module.exports diff --git a/packages/plugin-intercept/package.json b/packages/plugin-intercept/package.json index d7a790b9f5..dae0af404c 100644 --- a/packages/plugin-intercept/package.json +++ b/packages/plugin-intercept/package.json @@ -1,7 +1,15 @@ { "name": "@bugsnag/plugin-intercept", "version": "8.4.0", - "main": "intercept.js", + "main": "dist/intercept.js", + "types": "dist/types/intercept.d.ts", + "exports": { + ".": { + "types": "./dist/types/intercept.d.ts", + "default": "./dist/intercept.js", + "import": "./dist/intercept.mjs" + } + }, "description": "@bugsnag/js plugin providing convenience functions for intercepting asynchronous errors", "homepage": "https://www.bugsnag.com/", "repository": { @@ -12,9 +20,8 @@ "access": "public" }, "files": [ - "*.js" + "dist" ], - "scripts": {}, "author": "Bugsnag", "license": "MIT", "devDependencies": { @@ -22,5 +29,11 @@ }, "peerDependencies": { "@bugsnag/core": "^8.0.0" + }, + "scripts": { + "build": "npm run build:npm", + "build:npm": "rollup --config rollup.config.npm.mjs", + "clean": "rm -rf dist/*", + "test:types": "tsc -p tsconfig.json" } } diff --git a/packages/plugin-intercept/rollup.config.npm.mjs b/packages/plugin-intercept/rollup.config.npm.mjs new file mode 100644 index 0000000000..72d96d9ea0 --- /dev/null +++ b/packages/plugin-intercept/rollup.config.npm.mjs @@ -0,0 +1,6 @@ +import createRollupConfig from "../../.rollup/index.mjs"; + +export default createRollupConfig({ + input: "src/intercept.ts", + external: [/node_modules/], +}); \ No newline at end of file diff --git a/packages/plugin-intercept/src/intercept.ts b/packages/plugin-intercept/src/intercept.ts new file mode 100644 index 0000000000..c57a25c530 --- /dev/null +++ b/packages/plugin-intercept/src/intercept.ts @@ -0,0 +1,53 @@ +import type { Plugin } from '@bugsnag/core' +import { nodeFallbackStack } from '@bugsnag/core' + +type ErrorCallback = () => void +type SuccessCallback = (...args: T) => void +type NodeCallback = (err: Error | null, ...data: T) => void + +interface InterceptFunction { + // Single callback (no error handler) + (cb: SuccessCallback): NodeCallback + // Error handler + callback + (onError: ErrorCallback, cb: SuccessCallback): NodeCallback +} + +const plugin: Plugin = { + name: 'intercept', + load: client => { + const intercept: InterceptFunction = ( + onError: ErrorCallback | SuccessCallback = () => {}, + cb?: SuccessCallback + ): NodeCallback => { + if (typeof cb !== 'function') { + // Single-parameter form: intercept(cb) + cb = onError as SuccessCallback + onError = () => {} + } + + // capture a stacktrace in case a resulting error has nothing + const fallbackStack = nodeFallbackStack.getStack() + + return (err: Error | null, ...data: T) => { + if (err) { + // check if the stacktrace has no context, if so, if so append the frames we created earlier + if (typeof err.stack === 'string' && fallbackStack) { + nodeFallbackStack.maybeUseFallbackStack(err, fallbackStack) + } + const event = client.Event.create(err, true, { + severity: 'warning', + unhandled: false, + severityReason: { type: 'callbackErrorIntercept' } + }, 'intercept()', 1) + client._notify(event, onError as ErrorCallback) + return + } + cb(...data) + } + } + + return intercept + } +} + +export default plugin diff --git a/packages/plugin-intercept/test/intercept.test.ts b/packages/plugin-intercept/test/intercept.test.ts index 986782f623..74f097660b 100644 --- a/packages/plugin-intercept/test/intercept.test.ts +++ b/packages/plugin-intercept/test/intercept.test.ts @@ -1,5 +1,5 @@ import { Client } from '@bugsnag/core' -import plugin from '../' +import plugin from '../src/intercept' import fs from 'fs' // mock an async resource diff --git a/packages/plugin-intercept/tsconfig.json b/packages/plugin-intercept/tsconfig.json new file mode 100644 index 0000000000..66a7db7b94 --- /dev/null +++ b/packages/plugin-intercept/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": { + "lib": ["es2017"], + "types": ["node"] + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index d764babac1..6dba77d34f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -28,7 +28,6 @@ "packages/plugin-restify", "packages/node", "packages/plugin-interaction-breadcrumbs", - "packages/plugin-intercept", "packages/browser" ], "exclude": [ From 2e742b46208c5616e6c547df0e32441152fad426 Mon Sep 17 00:00:00 2001 From: AnastasiiaSvietlova <119674359+AnastasiiaSvietlova@users.noreply.github.com> Date: Mon, 8 Sep 2025 14:41:49 +0200 Subject: [PATCH 11/17] Convert @bugsnag/plugin-contextualize to TypeScript (#2540) * Convert @bugsnag/plugin-node-device to TypeScript (#2505) * convert plugin-node-device * fix type errors and update test * fix export * made value optional * fix test * add os to rollup * Convert @bugsnag/plugin-node-in-project to TypeScript (#2506) * convert plugin-node-in-project * fix types and rollup config * update rollup * update package json * Convert @bugsnag/plugin-node-uncaught-exception to TypeScript (#2509) * convert uncaught-exception to typescript * update types * update package json * update build * Convert @bugsnag/plugin-node-unhandled-rejection to TypeScript (#2511) * convert unhandled-rejection to typescript * update package json * update package-lock * Convert @bugsnag/plugin-node-surrounding-code to TypeScript (#2507) * convert node-surrounding-code * update rollup config * update types and test * delete commented line * update package json * update package-lock * update package-lock * Convert @bugsnag/plugin-strip-project-root to TypeScript (#2520) * convert plugin strip project root to TypeScript * update import * Convert @bugsnag/plugin-server-session to TypeScript (#2514) * convert server session to typescript * update package-lock * add type declaration file for backo * update types * update types * update types and tests * update types * convert contextualize to TS * update rollup config * add space --- .../plugin-contextualize/contextualize.js | 27 -------------- packages/plugin-contextualize/package.json | 18 ++++++++-- .../rollup.config.npm.mjs | 6 ++++ .../plugin-contextualize/src/contextualize.ts | 35 +++++++++++++++++++ packages/plugin-contextualize/tsconfig.json | 8 +++++ tsconfig.json | 1 - 6 files changed, 65 insertions(+), 30 deletions(-) delete mode 100644 packages/plugin-contextualize/contextualize.js create mode 100644 packages/plugin-contextualize/rollup.config.npm.mjs create mode 100644 packages/plugin-contextualize/src/contextualize.ts create mode 100644 packages/plugin-contextualize/tsconfig.json diff --git a/packages/plugin-contextualize/contextualize.js b/packages/plugin-contextualize/contextualize.js deleted file mode 100644 index 5097089475..0000000000 --- a/packages/plugin-contextualize/contextualize.js +++ /dev/null @@ -1,27 +0,0 @@ -const { cloneClient, nodeFallbackStack } = require('@bugsnag/core') - -module.exports = { - name: 'contextualize', - load: client => { - const contextualize = (fn, onError) => { - // capture a stacktrace in case a resulting error has nothing - const fallbackStack = nodeFallbackStack.getStack() - - const clonedClient = cloneClient(client) - - // add the stacktrace to the cloned client so it can be used later - // by the uncaught exception handler. Note the unhandled rejection - // handler does not need this because it gets a stacktrace - clonedClient.fallbackStack = fallbackStack - - clonedClient.addOnError(onError) - - client._clientContext.run(clonedClient, fn) - } - - return contextualize - } -} - -// add a default export for ESM modules without interop -module.exports.default = module.exports diff --git a/packages/plugin-contextualize/package.json b/packages/plugin-contextualize/package.json index 757af50bf0..8531321b64 100644 --- a/packages/plugin-contextualize/package.json +++ b/packages/plugin-contextualize/package.json @@ -1,7 +1,15 @@ { "name": "@bugsnag/plugin-contextualize", "version": "8.4.0", - "main": "contextualize.js", + "main": "dist/contextualize.js", + "types": "dist/types/contextualize.d.ts", + "exports": { + ".": { + "types": "./dist/types/contextualize.d.ts", + "default": "./dist/contextualize.js", + "import": "./dist/contextualize.mjs" + } + }, "description": "@bugsnag/js plugin to add context to unhandled events", "homepage": "https://www.bugsnag.com/", "repository": { @@ -12,7 +20,7 @@ "access": "public" }, "files": [ - "*.js" + "dist" ], "author": "Bugsnag", "license": "MIT", @@ -21,5 +29,11 @@ }, "peerDependencies": { "@bugsnag/core": "^8.0.0" + }, + "scripts": { + "build": "npm run build:npm", + "build:npm": "rollup --config rollup.config.npm.mjs", + "clean": "rm -rf dist/*", + "test:types": "tsc -p tsconfig.json" } } diff --git a/packages/plugin-contextualize/rollup.config.npm.mjs b/packages/plugin-contextualize/rollup.config.npm.mjs new file mode 100644 index 0000000000..dccd2ed5ed --- /dev/null +++ b/packages/plugin-contextualize/rollup.config.npm.mjs @@ -0,0 +1,6 @@ +import createRollupConfig from "../../.rollup/index.mjs" + +export default createRollupConfig({ + input: "src/contextualize.ts", + external: ['async_hooks'], +}) \ No newline at end of file diff --git a/packages/plugin-contextualize/src/contextualize.ts b/packages/plugin-contextualize/src/contextualize.ts new file mode 100644 index 0000000000..021ee611c9 --- /dev/null +++ b/packages/plugin-contextualize/src/contextualize.ts @@ -0,0 +1,35 @@ +import type { Client, OnErrorCallback, Plugin } from '@bugsnag/core' +import { cloneClient, nodeFallbackStack } from '@bugsnag/core' +import { AsyncLocalStorage } from 'async_hooks' + +interface InternalClient extends Client { + _clientContext: AsyncLocalStorage + fallbackStack?: string | undefined +} + +const plugin: Plugin = { + name: 'contextualize', + load: client => { + const internalClient = client as InternalClient + + const contextualize = (fn: () => void, onError: OnErrorCallback) => { + // capture a stacktrace in case a resulting error has nothing + const fallbackStack = nodeFallbackStack.getStack() + + const clonedClient = cloneClient(internalClient) as InternalClient + + // add the stacktrace to the cloned client so it can be used later + // by the uncaught exception handler. Note the unhandled rejection + // handler does not need this because it gets a stacktrace + clonedClient.fallbackStack = fallbackStack + + clonedClient.addOnError(onError) + + internalClient._clientContext.run(clonedClient, fn) + } + + return contextualize + } +} + +export default plugin diff --git a/packages/plugin-contextualize/tsconfig.json b/packages/plugin-contextualize/tsconfig.json new file mode 100644 index 0000000000..66a7db7b94 --- /dev/null +++ b/packages/plugin-contextualize/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": { + "lib": ["es2017"], + "types": ["node"] + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 6dba77d34f..b0f63e08c6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,7 +19,6 @@ "packages/delivery-react-native", "packages/in-flight", "packages/plugin-aws-lambda", - "packages/plugin-contextualize", "packages/plugin-navigation-breadcrumbs", "packages/plugin-react", "packages/plugin-vue", From 0c8b9712e45892adcdf67873b5f05cec3affaf17 Mon Sep 17 00:00:00 2001 From: AnastasiiaSvietlova <119674359+AnastasiiaSvietlova@users.noreply.github.com> Date: Mon, 8 Sep 2025 15:16:22 +0200 Subject: [PATCH 12/17] Convert @bugsnag/plugin-stackframe-path-normaliser to TypeScript (#2541) * Convert @bugsnag/plugin-node-device to TypeScript (#2505) * convert plugin-node-device * fix type errors and update test * fix export * made value optional * fix test * add os to rollup * Convert @bugsnag/plugin-node-in-project to TypeScript (#2506) * convert plugin-node-in-project * fix types and rollup config * update rollup * update package json * Convert @bugsnag/plugin-node-uncaught-exception to TypeScript (#2509) * convert uncaught-exception to typescript * update types * update package json * update build * Convert @bugsnag/plugin-node-unhandled-rejection to TypeScript (#2511) * convert unhandled-rejection to typescript * update package json * update package-lock * Convert @bugsnag/plugin-node-surrounding-code to TypeScript (#2507) * convert node-surrounding-code * update rollup config * update types and test * delete commented line * update package json * update package-lock * update package-lock * Convert @bugsnag/plugin-strip-project-root to TypeScript (#2520) * convert plugin strip project root to TypeScript * update import * Convert @bugsnag/plugin-server-session to TypeScript (#2514) * convert server session to typescript * update package-lock * add type declaration file for backo * update types * update types * update types and tests * update types * convert stackframe-path-normaliser to TS --- .../package.json | 19 ++++++++++++++++++- .../rollup.config.npm.mjs | 6 ++++++ .../path-normaliser.ts} | 8 ++++++-- .../test/path-normaliser.test.ts | 2 +- .../tsconfig.json | 8 ++++++++ 5 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 packages/plugin-stackframe-path-normaliser/rollup.config.npm.mjs rename packages/plugin-stackframe-path-normaliser/{path-normaliser.js => src/path-normaliser.ts} (53%) create mode 100644 packages/plugin-stackframe-path-normaliser/tsconfig.json diff --git a/packages/plugin-stackframe-path-normaliser/package.json b/packages/plugin-stackframe-path-normaliser/package.json index 1b607806ee..ebb2d15018 100644 --- a/packages/plugin-stackframe-path-normaliser/package.json +++ b/packages/plugin-stackframe-path-normaliser/package.json @@ -1,13 +1,24 @@ { "name": "@bugsnag/plugin-stackframe-path-normaliser", "version": "8.4.0", - "main": "path-normaliser.js", + "main": "dist/path-normaliser.js", + "types": "dist/types/path-normaliser.d.ts", + "exports": { + ".": { + "types": "./dist/types/path-normaliser.d.ts", + "default": "./dist/path-normaliser.js", + "import": "./dist/path-normaliser.mjs" + } + }, "description": "@bugsnag/js plugin to normalise file paths in stackframes", "homepage": "https://www.bugsnag.com/", "repository": { "type": "git", "url": "git@github.com:bugsnag/bugsnag-js.git" }, + "files": [ + "dist" + ], "publishConfig": { "access": "public" }, @@ -18,5 +29,11 @@ }, "devDependencies": { "@bugsnag/core": "^8.4.0" + }, + "scripts": { + "build": "npm run build:npm", + "build:npm": "rollup --config rollup.config.npm.mjs", + "clean": "rm -rf dist/*", + "test:types": "tsc -p tsconfig.json" } } diff --git a/packages/plugin-stackframe-path-normaliser/rollup.config.npm.mjs b/packages/plugin-stackframe-path-normaliser/rollup.config.npm.mjs new file mode 100644 index 0000000000..c4e52497e7 --- /dev/null +++ b/packages/plugin-stackframe-path-normaliser/rollup.config.npm.mjs @@ -0,0 +1,6 @@ +import createRollupConfig from "../../.rollup/index.mjs" + +export default createRollupConfig({ + input: "src/path-normaliser.ts", + external: [/node_modules/], +}) \ No newline at end of file diff --git a/packages/plugin-stackframe-path-normaliser/path-normaliser.js b/packages/plugin-stackframe-path-normaliser/src/path-normaliser.ts similarity index 53% rename from packages/plugin-stackframe-path-normaliser/path-normaliser.js rename to packages/plugin-stackframe-path-normaliser/src/path-normaliser.ts index 3e656d07d4..5ae23c4480 100644 --- a/packages/plugin-stackframe-path-normaliser/path-normaliser.js +++ b/packages/plugin-stackframe-path-normaliser/src/path-normaliser.ts @@ -1,7 +1,9 @@ -module.exports = { +import type { Plugin, Stackframe } from '@bugsnag/core' + +const plugin: Plugin = { load (client) { client.addOnError(event => { - const allFrames = event.errors.reduce((accum, er) => accum.concat(er.stacktrace), []) + const allFrames: Stackframe[] = event.errors.reduce((accum: Stackframe[], er) => accum.concat(er.stacktrace), []) allFrames.forEach(stackframe => { if (typeof stackframe.file !== 'string') { @@ -13,3 +15,5 @@ module.exports = { }) } } + +export default plugin diff --git a/packages/plugin-stackframe-path-normaliser/test/path-normaliser.test.ts b/packages/plugin-stackframe-path-normaliser/test/path-normaliser.test.ts index 82c3b7427d..07070d657e 100644 --- a/packages/plugin-stackframe-path-normaliser/test/path-normaliser.test.ts +++ b/packages/plugin-stackframe-path-normaliser/test/path-normaliser.test.ts @@ -1,4 +1,4 @@ -import plugin from '../' +import plugin from '../src/path-normaliser' import { Client, Event } from '@bugsnag/core' describe('plugin: stackframe path normaliser', () => { diff --git a/packages/plugin-stackframe-path-normaliser/tsconfig.json b/packages/plugin-stackframe-path-normaliser/tsconfig.json new file mode 100644 index 0000000000..66a7db7b94 --- /dev/null +++ b/packages/plugin-stackframe-path-normaliser/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": { + "lib": ["es2017"], + "types": ["node"] + } +} \ No newline at end of file From d9ca5e4e002c874a7cff10c9b13c7bd988c23f2a Mon Sep 17 00:00:00 2001 From: Ben Wilson Date: Tue, 16 Sep 2025 17:59:25 +0100 Subject: [PATCH 13/17] update package-lock.json --- package-lock.json | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index c89e727785..b0cc600919 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3954,16 +3954,26 @@ "node": ">=6.9.0" } }, + "node_modules/@inquirer/ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.0.tgz", + "integrity": "sha512-JWaTfCxI1eTmJ1BIv86vUfjVatOdxwD0DAVKYevY8SazeUUZtW+tNbsdejVO1GYE0GXJW1N1ahmiC3TFd+7wZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@inquirer/core": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.2.0.tgz", - "integrity": "sha512-NyDSjPqhSvpZEMZrLCYUquWNl+XC/moEcVFqS55IEYIYsY0a1cUCevSqk7ctOlnm/RaSBU5psFryNlxcmGrjaA==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.2.2.tgz", + "integrity": "sha512-yXq/4QUnk4sHMtmbd7irwiepjB8jXU0kkFRL4nr/aDBA2mDz13cMakEWdDwX3eSCTkk03kwcndD1zfRAIlELxA==", "dev": true, "license": "MIT", "dependencies": { + "@inquirer/ansi": "^1.0.0", "@inquirer/figures": "^1.0.13", "@inquirer/type": "^3.0.8", - "ansi-escapes": "^4.3.2", "cli-width": "^4.1.0", "mute-stream": "^2.0.0", "signal-exit": "^4.1.0", @@ -53972,15 +53982,21 @@ "integrity": "sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==", "dev": true }, + "@inquirer/ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.0.tgz", + "integrity": "sha512-JWaTfCxI1eTmJ1BIv86vUfjVatOdxwD0DAVKYevY8SazeUUZtW+tNbsdejVO1GYE0GXJW1N1ahmiC3TFd+7wZA==", + "dev": true + }, "@inquirer/core": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.2.0.tgz", - "integrity": "sha512-NyDSjPqhSvpZEMZrLCYUquWNl+XC/moEcVFqS55IEYIYsY0a1cUCevSqk7ctOlnm/RaSBU5psFryNlxcmGrjaA==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.2.2.tgz", + "integrity": "sha512-yXq/4QUnk4sHMtmbd7irwiepjB8jXU0kkFRL4nr/aDBA2mDz13cMakEWdDwX3eSCTkk03kwcndD1zfRAIlELxA==", "dev": true, "requires": { + "@inquirer/ansi": "^1.0.0", "@inquirer/figures": "^1.0.13", "@inquirer/type": "^3.0.8", - "ansi-escapes": "^4.3.2", "cli-width": "^4.1.0", "mute-stream": "^2.0.0", "signal-exit": "^4.1.0", From b776d02b05cea30e540205431fb2a92da2d71acf Mon Sep 17 00:00:00 2001 From: AnastasiiaSvietlova <119674359+AnastasiiaSvietlova@users.noreply.github.com> Date: Tue, 16 Sep 2025 20:09:04 +0200 Subject: [PATCH 14/17] Convert @bugsnag/delivery-node to TypeScript (#2545) * Convert @bugsnag/plugin-node-device to TypeScript (#2505) * convert plugin-node-device * fix type errors and update test * fix export * made value optional * fix test * add os to rollup * Convert @bugsnag/plugin-node-in-project to TypeScript (#2506) * convert plugin-node-in-project * fix types and rollup config * update rollup * update package json * Convert @bugsnag/plugin-node-uncaught-exception to TypeScript (#2509) * convert uncaught-exception to typescript * update types * update package json * update build * Convert @bugsnag/plugin-node-unhandled-rejection to TypeScript (#2511) * convert unhandled-rejection to typescript * update package json * update package-lock * Convert @bugsnag/plugin-node-surrounding-code to TypeScript (#2507) * convert node-surrounding-code * update rollup config * update types and test * delete commented line * update package json * update package-lock * update package-lock * Convert @bugsnag/plugin-strip-project-root to TypeScript (#2520) * convert plugin strip project root to TypeScript * update import * Convert @bugsnag/plugin-server-session to TypeScript (#2514) * convert server session to typescript * update package-lock * add type declaration file for backo * update types * update types * update types and tests * update types * convert delivery-node to TS * convert delivery and request * update types for delivery * fix build * fix rollup.config * fix tsconfig --- packages/delivery-node/delivery.js | 64 --------------- packages/delivery-node/package.json | 18 ++++- packages/delivery-node/rollup.config.npm.mjs | 6 ++ packages/delivery-node/src/delivery.ts | 79 +++++++++++++++++++ .../{request.js => src/request.ts} | 23 ++++-- packages/delivery-node/test/delivery.test.ts | 2 +- packages/delivery-node/tsconfig.json | 8 ++ tsconfig.json | 1 - 8 files changed, 126 insertions(+), 75 deletions(-) delete mode 100644 packages/delivery-node/delivery.js create mode 100644 packages/delivery-node/rollup.config.npm.mjs create mode 100644 packages/delivery-node/src/delivery.ts rename packages/delivery-node/{request.js => src/request.ts} (59%) create mode 100644 packages/delivery-node/tsconfig.json diff --git a/packages/delivery-node/delivery.js b/packages/delivery-node/delivery.js deleted file mode 100644 index e1e0afe3ad..0000000000 --- a/packages/delivery-node/delivery.js +++ /dev/null @@ -1,64 +0,0 @@ -const jsonPayload = require('@bugsnag/json-payload') -const request = require('./request') - -module.exports = (client) => ({ - sendEvent: (event, cb = () => {}) => { - const body = jsonPayload.event(event, client._config.redactedKeys) - - const _cb = err => { - if (err) client._logger.error(`Event failed to send…\n${(err && err.stack) ? err.stack : err}`, err) - if (body.length > 10e5) { - client._logger.warn(`Event oversized (${(body.length / 10e5).toFixed(2)} MB)`) - } - cb(err) - } - - if (client._config.endpoints.notify === null) { - const err = new Error('Event not sent due to incomplete endpoint configuration') - return _cb(err) - } - - try { - request({ - url: client._config.endpoints.notify, - headers: { - 'Content-Type': 'application/json', - 'Bugsnag-Api-Key': event.apiKey || client._config.apiKey, - 'Bugsnag-Payload-Version': '4', - 'Bugsnag-Sent-At': (new Date()).toISOString() - }, - body, - agent: client._config.agent - }, (err, body) => _cb(err)) - } catch (e) { - _cb(e) - } - }, - sendSession: (session, cb = () => {}) => { - const _cb = err => { - if (err) client._logger.error(`Session failed to send…\n${(err && err.stack) ? err.stack : err}`, err) - cb(err) - } - - if (client._config.endpoints.session === null) { - const err = new Error('Session not sent due to incomplete endpoint configuration') - return _cb(err) - } - - try { - request({ - url: client._config.endpoints.sessions, - headers: { - 'Content-Type': 'application/json', - 'Bugsnag-Api-Key': client._config.apiKey, - 'Bugsnag-Payload-Version': '1', - 'Bugsnag-Sent-At': (new Date()).toISOString() - }, - body: jsonPayload.session(session, client._config.redactedKeys), - agent: client._config.agent - }, err => _cb(err)) - } catch (e) { - _cb(e) - } - } -}) diff --git a/packages/delivery-node/package.json b/packages/delivery-node/package.json index 3c38648429..e3873cc07b 100644 --- a/packages/delivery-node/package.json +++ b/packages/delivery-node/package.json @@ -1,7 +1,15 @@ { "name": "@bugsnag/delivery-node", "version": "8.4.0", - "main": "delivery.js", + "main": "dist/delivery.js", + "types": "dist/types/delivery.d.ts", + "exports": { + ".": { + "types": "./dist/types/delivery.d.ts", + "default": "./dist/delivery.js", + "import": "./dist/delivery.mjs" + } + }, "description": "@bugsnag/node delivery mechanism", "homepage": "https://www.bugsnag.com/", "repository": { @@ -12,10 +20,16 @@ "access": "public" }, "files": [ - "*.js" + "dist" ], "author": "Bugsnag", "license": "MIT", + "scripts": { + "build": "npm run build:npm", + "build:npm": "rollup --config rollup.config.npm.mjs", + "clean": "rm -rf dist/*", + "test:types": "tsc -p tsconfig.json" + }, "devDependencies": { "@bugsnag/core": "^8.4.0" }, diff --git a/packages/delivery-node/rollup.config.npm.mjs b/packages/delivery-node/rollup.config.npm.mjs new file mode 100644 index 0000000000..60ad26397d --- /dev/null +++ b/packages/delivery-node/rollup.config.npm.mjs @@ -0,0 +1,6 @@ +import createRollupConfig from "../../.rollup/index.mjs" + +export default createRollupConfig({ + input: "src/delivery.ts", + external: ['http', 'https', 'url'], +}) \ No newline at end of file diff --git a/packages/delivery-node/src/delivery.ts b/packages/delivery-node/src/delivery.ts new file mode 100644 index 0000000000..332fe5f6df --- /dev/null +++ b/packages/delivery-node/src/delivery.ts @@ -0,0 +1,79 @@ +import type { Client, Config, Delivery } from '@bugsnag/core' +import * as jsonPayload from '@bugsnag/json-payload' +import request from './request' +import http from 'http' + +interface PluginConfig extends Config { + agent?: http.Agent +} + +interface InternalClient extends Client { + _config: Required +} + +const delivery = (client: Client): Delivery => ({ + sendEvent: (event, cb = () => {}) => { + const internalClient = client as InternalClient + const body = jsonPayload.event(event, internalClient._config.redactedKeys) + + const _cb = (err: Error | null) => { + if (err) internalClient._logger.error(`Event failed to send…\n${(err && err.stack) ? err.stack : err}`, err) + if (body.length > 10e5) { + internalClient._logger.warn(`Event oversized (${(body.length / 10e5).toFixed(2)} MB)`) + } + cb(err) + } + + if (internalClient._config.endpoints.notify === null) { + const err = new Error('Event not sent due to incomplete endpoint configuration') + return _cb(err) + } + + try { + request({ + url: internalClient._config.endpoints.notify, + headers: { + 'Content-Type': 'application/json', + 'Bugsnag-Api-Key': event.apiKey || internalClient._config.apiKey, + 'Bugsnag-Payload-Version': '4', + 'Bugsnag-Sent-At': (new Date()).toISOString() + }, + body, + agent: internalClient._config.agent + }, (err) => _cb(err)) + } catch (e: any) { + _cb(e) + } + }, + sendSession: (session, cb = () => {}) => { + const internalClient = client as InternalClient + const _cb = (err: Error | null) => { + if (err) internalClient._logger.error(`Session failed to send…\n${(err && err.stack) ? err.stack : err}`, err) + cb(err) + } + + if (internalClient._config.endpoints.sessions === null) { + const err = new Error('Session not sent due to incomplete endpoint configuration') + return _cb(err) + } + + try { + request({ + url: internalClient._config.endpoints.sessions, + headers: { + 'Content-Type': 'application/json', + 'Bugsnag-Api-Key': internalClient._config.apiKey, + 'Bugsnag-Payload-Version': '1', + 'Bugsnag-Sent-At': (new Date()).toISOString() + }, + body: jsonPayload.session(session, internalClient._config.redactedKeys), + agent: internalClient._config.agent + }, err => _cb(err)) + } catch (e: any) { + _cb(e) + } + } +}) + + +export default delivery \ No newline at end of file diff --git a/packages/delivery-node/request.js b/packages/delivery-node/src/request.ts similarity index 59% rename from packages/delivery-node/request.js rename to packages/delivery-node/src/request.ts index d60b0fb2c8..d36d5d1588 100644 --- a/packages/delivery-node/request.js +++ b/packages/delivery-node/src/request.ts @@ -1,10 +1,17 @@ -const http = require('http') -const https = require('https') -const { parse } = require('url') +import http from 'http' +import https from 'https' +import { parse } from 'url' -module.exports = ({ url, headers, body, agent }, cb) => { +interface RequestOptions { + url: string + headers?: http.OutgoingHttpHeaders + body?: string + agent?: http.Agent +} + +const request = ({ url, headers, body, agent }: RequestOptions, cb: (err: Error | null, body?: string) => void) => { let didError = false - const onError = (err) => { + const onError = (err: Error) => { if (didError) return didError = true cb(err) @@ -25,7 +32,7 @@ module.exports = ({ url, headers, body, agent }, cb) => { req.on('response', res => { bufferResponse(res, (err, body) => { if (err) return onError(err) - if (res.statusCode < 200 || res.statusCode >= 300) { + if (res.statusCode && (res.statusCode < 200 || res.statusCode >= 300)) { return onError(new Error(`Bad statusCode from API: ${res.statusCode}\n${body}`)) } cb(null, body) @@ -35,10 +42,12 @@ module.exports = ({ url, headers, body, agent }, cb) => { req.end() } -const bufferResponse = (stream, cb) => { +const bufferResponse = (stream: NodeJS.ReadableStream, cb: (err: Error | null, body?: string) => void) => { let data = '' stream.on('error', cb) stream.setEncoding('utf8') stream.on('data', d => { data += d }) stream.on('end', () => cb(null, data)) } + +export default request \ No newline at end of file diff --git a/packages/delivery-node/test/delivery.test.ts b/packages/delivery-node/test/delivery.test.ts index 787102ce6f..0e05eba5de 100644 --- a/packages/delivery-node/test/delivery.test.ts +++ b/packages/delivery-node/test/delivery.test.ts @@ -1,4 +1,4 @@ -import delivery from '../' +import delivery from '../src/delivery' import http from 'http' import type { Client, EventDeliveryPayload, SessionDeliveryPayload } from '@bugsnag/core' import type { AddressInfo } from 'net' diff --git a/packages/delivery-node/tsconfig.json b/packages/delivery-node/tsconfig.json new file mode 100644 index 0000000000..66a7db7b94 --- /dev/null +++ b/packages/delivery-node/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": { + "lib": ["es2017"], + "types": ["node"] + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index b0f63e08c6..bae0828a7f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,7 +15,6 @@ }, "include": [ "packages/core", - "packages/delivery-node", "packages/delivery-react-native", "packages/in-flight", "packages/plugin-aws-lambda", From fecbcddc2a24d02930c5a48030614a589f0aa40f Mon Sep 17 00:00:00 2001 From: AnastasiiaSvietlova <119674359+AnastasiiaSvietlova@users.noreply.github.com> Date: Thu, 18 Sep 2025 15:20:55 +0200 Subject: [PATCH 15/17] Convert @bugsnag/plugin-express to TypeScript (#2546) * add tsconfig * convert plugin express to ts * update rollup config * delete old version * update export to pass tests * update types consistency * update export * refactor types of request * refactor import BugsnagPluginExpress * update export express plugin * delete type casting --- packages/plugin-express/package.json | 20 ++- packages/plugin-express/rollup.config.npm.mjs | 6 + packages/plugin-express/src/express.js | 83 ------------ packages/plugin-express/src/express.ts | 128 ++++++++++++++++++ packages/plugin-express/src/request-info.js | 38 ------ packages/plugin-express/src/request-info.ts | 85 ++++++++++++ packages/plugin-express/tsconfig.json | 8 ++ .../plugin-express/types/bugsnag-express.d.ts | 29 ---- tsconfig.json | 1 - 9 files changed, 243 insertions(+), 155 deletions(-) create mode 100644 packages/plugin-express/rollup.config.npm.mjs delete mode 100644 packages/plugin-express/src/express.js create mode 100644 packages/plugin-express/src/express.ts delete mode 100644 packages/plugin-express/src/request-info.js create mode 100644 packages/plugin-express/src/request-info.ts create mode 100644 packages/plugin-express/tsconfig.json delete mode 100644 packages/plugin-express/types/bugsnag-express.d.ts diff --git a/packages/plugin-express/package.json b/packages/plugin-express/package.json index 747566e850..a7794f37a6 100644 --- a/packages/plugin-express/package.json +++ b/packages/plugin-express/package.json @@ -1,8 +1,15 @@ { "name": "@bugsnag/plugin-express", "version": "8.4.0", - "main": "src/express.js", - "types": "types/bugsnag-express.d.ts", + "main": "dist/express.js", + "types": "dist/types/express.d.ts", + "exports": { + ".": { + "types": "./dist/types/express.d.ts", + "default": "./dist/express.js", + "import": "./dist/express.mjs" + } + }, "description": "@bugsnag/js error handling middleware for Express (and Connect) web servers", "homepage": "https://www.bugsnag.com/", "repository": { @@ -13,8 +20,7 @@ "access": "public" }, "files": [ - "src", - "types" + "dist" ], "author": "Bugsnag", "license": "MIT", @@ -24,5 +30,11 @@ "devDependencies": { "@bugsnag/core": "^8.4.0", "@types/express": "4.17.13" + }, + "scripts": { + "build": "npm run build:npm", + "build:npm": "rollup --config rollup.config.npm.mjs", + "clean": "rm -rf dist/*", + "test:types": "tsc -p tsconfig.json" } } diff --git a/packages/plugin-express/rollup.config.npm.mjs b/packages/plugin-express/rollup.config.npm.mjs new file mode 100644 index 0000000000..be683dedc5 --- /dev/null +++ b/packages/plugin-express/rollup.config.npm.mjs @@ -0,0 +1,6 @@ +import createRollupConfig from "../../.rollup/index.mjs" + +export default createRollupConfig({ + input: "src/express.ts", + external: ["express", "net", "async_hooks"], +}) \ No newline at end of file diff --git a/packages/plugin-express/src/express.js b/packages/plugin-express/src/express.js deleted file mode 100644 index 5050593a41..0000000000 --- a/packages/plugin-express/src/express.js +++ /dev/null @@ -1,83 +0,0 @@ -const extractRequestInfo = require('./request-info') -const { cloneClient } = require('@bugsnag/core') -const handledState = { - severity: 'error', - unhandled: true, - severityReason: { - type: 'unhandledErrorMiddleware', - attributes: { framework: 'Express/Connect' } - } -} - -module.exports = { - name: 'express', - load: client => { - const requestHandler = (req, res, next) => { - // clone the client to be scoped to this request. If sessions are enabled, start one - const requestClient = cloneClient(client) - if (requestClient._config.autoTrackSessions) { - requestClient.startSession() - } - - // attach it to the request - req.bugsnag = requestClient - - // extract request info and pass it to the relevant bugsnag properties - requestClient.addOnError((event) => { - const { metadata, request } = getRequestAndMetadataFromReq(req) - event.request = { ...event.request, ...request } - event.addMetadata('request', metadata) - if (event._handledState.severityReason.type === 'unhandledException') { - event.severity = 'error' - event._handledState = handledState - } - }, true) - - client._clientContext.run(requestClient, next) - } - - const errorHandler = (err, req, res, next) => { - if (!client._config.autoDetectErrors) return next(err) - - const event = client.Event.create(err, false, handledState, 'express middleware', 1) - - const { metadata, request } = getRequestAndMetadataFromReq(req) - event.request = { ...event.request, ...request } - event.addMetadata('request', metadata) - - if (req.bugsnag) { - req.bugsnag._notify(event) - } else { - client._logger.warn( - 'req.bugsnag is not defined. Make sure the @bugsnag/plugin-express requestHandler middleware is added first.' - ) - client._notify(event) - } - - next(err) - } - - const runInContext = (req, res, next) => { - client._clientContext.run(req.bugsnag, next) - } - - return { requestHandler, errorHandler, runInContext } - } -} - -const getRequestAndMetadataFromReq = req => { - const { body, ...requestInfo } = extractRequestInfo(req) - return { - metadata: requestInfo, - request: { - body, - clientIp: requestInfo.clientIp, - headers: requestInfo.headers, - httpMethod: requestInfo.httpMethod, - url: requestInfo.url, - referer: requestInfo.referer - } - } -} - -module.exports.default = module.exports diff --git a/packages/plugin-express/src/express.ts b/packages/plugin-express/src/express.ts new file mode 100644 index 0000000000..ab71537abe --- /dev/null +++ b/packages/plugin-express/src/express.ts @@ -0,0 +1,128 @@ +import type { Client, Plugin } from '@bugsnag/core' +import { cloneClient } from '@bugsnag/core' +import { AsyncLocalStorage } from 'async_hooks' +import type { ErrorRequestHandler, NextFunction, Request, Response } from 'express' +import * as express from 'express' +import extractRequestInfo from './request-info' +import type { RequestInfo } from './request-info' + +// Extend Express Request interface to include bugsnag client +declare module 'express-serve-static-core' { + interface Request { + bugsnag?: Client + } +} + +// Add getPlugin method type augmentation +declare module '@bugsnag/core' { + interface Client { + getPlugin(id: 'express'): BugsnagPluginExpressResult | undefined + } +} + +interface BugsnagPluginExpressResult { + errorHandler: ErrorRequestHandler + requestHandler: express.RequestHandler + runInContext: express.RequestHandler +} + +interface ExtractedRequestData { + metadata: Omit + request: { + body: RequestInfo['body'] + clientIp: RequestInfo['clientIp'] + headers: RequestInfo['headers'] + httpMethod: RequestInfo['httpMethod'] + url: RequestInfo['url'] + referer: RequestInfo['referer'] + } +} + +interface InternalClient extends Client { + _clientContext: AsyncLocalStorage +} + +const handledState = { + severity: 'error' as const, + unhandled: true, + severityReason: { + type: 'unhandledErrorMiddleware' as const, + attributes: { framework: 'Express/Connect' } + } +} + +const plugin: Plugin = { + name: 'express', + load: (client: Client): BugsnagPluginExpressResult => { + const internalClient = client as InternalClient + const requestHandler = (req: Request, res: Response, next: NextFunction) => { + // clone the client to be scoped to this request. If sessions are enabled, start one + const requestClient = cloneClient(internalClient) + if (requestClient._config.autoTrackSessions) { + requestClient.startSession() + } + + // attach it to the request + req.bugsnag = requestClient + + // extract request info and pass it to the relevant bugsnag properties + requestClient.addOnError((event) => { + const { metadata, request } = getRequestAndMetadataFromReq(req) + event.request = { ...event.request, ...request } + event.addMetadata('request', metadata) + if (event._handledState.severityReason.type === 'unhandledException') { + event.severity = 'error'; + // @ts-expect-error override readonly property + event._handledState = handledState + } + }, true) + + internalClient._clientContext.run(requestClient, next) + } + + const errorHandler: ErrorRequestHandler = (err: Error, req: Request, res: Response, next: NextFunction) => { + if (!internalClient._config.autoDetectErrors) return next(err) + + const event = internalClient.Event.create(err, false, handledState, 'express middleware', 1) + + const { metadata, request } = getRequestAndMetadataFromReq(req) + event.request = { ...event.request, ...request } + event.addMetadata('request', metadata) + + if (req.bugsnag) { + req.bugsnag._notify(event) + } else { + internalClient._logger.warn( + 'req.bugsnag is not defined. Make sure the @bugsnag/plugin-express requestHandler middleware is added first.' + ) + internalClient._notify(event) + } + + next(err) + } + + const runInContext = (req: Request, res: Response, next: NextFunction) => { + (client as InternalClient)._clientContext.run(req.bugsnag as Client, next) + } + + return { requestHandler, errorHandler, runInContext } + } +} + +const getRequestAndMetadataFromReq = (req: Request): ExtractedRequestData => { + const { body, ...requestInfo } = extractRequestInfo(req as Request) + return { + metadata: requestInfo, + request: { + body, + clientIp: requestInfo.clientIp, + headers: requestInfo.headers, + httpMethod: requestInfo.httpMethod, + url: requestInfo.url, + referer: requestInfo.referer + } + } +} + +export default plugin +module.exports = plugin \ No newline at end of file diff --git a/packages/plugin-express/src/request-info.js b/packages/plugin-express/src/request-info.js deleted file mode 100644 index 52f7cbdf13..0000000000 --- a/packages/plugin-express/src/request-info.js +++ /dev/null @@ -1,38 +0,0 @@ -const { extractObject } = require('@bugsnag/core') - -module.exports = req => { - const connection = req.connection - const address = connection && connection.address && connection.address() - const portNumber = address && address.port - const port = (!portNumber || portNumber === 80 || portNumber === 443) ? '' : `:${portNumber}` - const protocol = typeof req.protocol !== 'undefined' ? req.protocol : (req.connection.encrypted ? 'https' : 'http') - const hostname = (req.hostname || req.host || req.headers.host || '').replace(/:\d+$/, '') - const url = `${protocol}://${hostname}${port}${req.url}` - const request = { - url: url, - path: req.path || req.url, - httpMethod: req.method, - headers: req.headers, - httpVersion: req.httpVersion - } - - request.params = extractObject(req, 'params') - request.query = extractObject(req, 'query') - request.body = extractObject(req, 'body') - - request.clientIp = req.ip || (connection ? connection.remoteAddress : undefined) - request.referer = req.headers.referer || req.headers.referrer - - if (connection) { - request.connection = { - remoteAddress: connection.remoteAddress, - remotePort: connection.remotePort, - bytesRead: connection.bytesRead, - bytesWritten: connection.bytesWritten, - localPort: portNumber, - localAddress: address ? address.address : undefined, - IPVersion: address ? address.family : undefined - } - } - return request -} diff --git a/packages/plugin-express/src/request-info.ts b/packages/plugin-express/src/request-info.ts new file mode 100644 index 0000000000..8dd438efa8 --- /dev/null +++ b/packages/plugin-express/src/request-info.ts @@ -0,0 +1,85 @@ +import { extractObject } from '@bugsnag/core' +import type { Request } from 'express' +import type { AddressInfo } from 'net' + +export interface RequestInfo { + url: string + path: string + httpMethod: string + headers: { [key: string]: string } + httpVersion: string + params?: Record + query?: Record + body?: Record + clientIp?: string + referer?: string + connection?: { + remoteAddress?: string + remotePort?: number + bytesRead?: number + bytesWritten?: number + localPort?: number + localAddress?: string + IPVersion?: string + } +} + +const getFirstHeader = (header: string | string[] | undefined): string | undefined => { + if (Array.isArray(header)) return header[0] + return header +} + +const isAddressInfo = (info: any): info is AddressInfo => { + return info && typeof info === 'object' && 'port' in info && 'address' in info && 'family' in info +} + +const extractRequestInfo = (req: Request): RequestInfo => { + const connection = req.socket || req.connection + const address = connection && connection.address && connection.address() + const portNumber = isAddressInfo(address) ? address.port : undefined + const port = (!portNumber || portNumber === 80 || portNumber === 443) ? '' : `:${portNumber}` + const protocol = typeof req.protocol !== 'undefined' ? req.protocol : (connection && 'encrypted' in connection && connection.encrypted ? 'https' : 'http') + const hostname = (req.hostname || req.host || req.headers.host || '').replace(/:\d+$/, '') + const url = `${protocol}://${hostname}${port}${req.url}` + + // Convert headers to the expected format + const formattedHeaders: { [key: string]: string } = {} + if (req.headers) { + Object.keys(req.headers).forEach(key => { + const value = req.headers[key] + if (value !== undefined) { + formattedHeaders[key] = Array.isArray(value) ? value[0] : value + } + }) + } + + const request: RequestInfo = { + url: url, + path: req.path || req.url, + httpMethod: req.method, + headers: formattedHeaders, + httpVersion: req.httpVersion + } + + request.params = extractObject(req, 'params') + request.query = extractObject(req, 'query') + request.body = extractObject(req, 'body') + + request.clientIp = req.ip || (connection ? connection.remoteAddress : undefined) + request.referer = getFirstHeader(req.headers.referer) || getFirstHeader(req.headers.referrer) + + if (connection) { + request.connection = { + remoteAddress: connection.remoteAddress, + remotePort: connection.remotePort, + bytesRead: connection.bytesRead, + bytesWritten: connection.bytesWritten, + localPort: portNumber, + localAddress: isAddressInfo(address) ? address.address : undefined, + IPVersion: isAddressInfo(address) ? address.family : undefined + } + } + return request +} + +export default extractRequestInfo \ No newline at end of file diff --git a/packages/plugin-express/tsconfig.json b/packages/plugin-express/tsconfig.json new file mode 100644 index 0000000000..66a7db7b94 --- /dev/null +++ b/packages/plugin-express/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": { + "lib": ["es2017"], + "types": ["node"] + } +} \ No newline at end of file diff --git a/packages/plugin-express/types/bugsnag-express.d.ts b/packages/plugin-express/types/bugsnag-express.d.ts deleted file mode 100644 index 62123c48a3..0000000000 --- a/packages/plugin-express/types/bugsnag-express.d.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Plugin, Client } from '@bugsnag/core' -import * as express from 'express' - -declare const bugsnagPluginExpress: Plugin -export default bugsnagPluginExpress - -interface BugsnagPluginExpressResult { - errorHandler: express.ErrorRequestHandler - requestHandler: express.RequestHandler - runInContext: express.RequestHandler -} - -// add a new call signature for the getPlugin() method that types the plugin result -declare module '@bugsnag/core' { - interface Client { - getPlugin(id: 'express'): BugsnagPluginExpressResult | undefined - } -} - -// define req.bugsnag for express request handlers by declaration merging on the -// global interfaces according to the pattern described in the DefinitelyTyped repo: -// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/0bd28530564c3da2e728518084f22648af3a683c/types/express-serve-static-core/index.d.ts#L18-L26 -declare global { - namespace Express { - export interface Request { - bugsnag?: Client - } - } -} diff --git a/tsconfig.json b/tsconfig.json index bae0828a7f..d4125e67d2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -21,7 +21,6 @@ "packages/plugin-navigation-breadcrumbs", "packages/plugin-react", "packages/plugin-vue", - "packages/plugin-express", "packages/plugin-koa", "packages/plugin-restify", "packages/node", From ebc1c1f6c35b5898ffabef39e28e15fddaefc1be Mon Sep 17 00:00:00 2001 From: AnastasiiaSvietlova <119674359+AnastasiiaSvietlova@users.noreply.github.com> Date: Thu, 18 Sep 2025 16:54:46 +0200 Subject: [PATCH 16/17] Convert @bugsnag/plugin-restify to TypeScript (#2549) * convert plugin-restify to ts * update types * refactor: :label: base custom types off existing restify request types * refactor headers type of request * delete unnecessary export * add unit and end-to-end tests * update package-lock * update event severity property * restore event as any type casting * test: :white_check_mark: remove unnecessary tests * delete added previously lines to tests --------- Co-authored-by: Ben Wilson --- packages/plugin-restify/package.json | 20 ++- packages/plugin-restify/rollup.config.npm.mjs | 6 + packages/plugin-restify/src/request-info.js | 36 ----- packages/plugin-restify/src/request-info.ts | 78 +++++++++++ packages/plugin-restify/src/restify.js | 77 ----------- packages/plugin-restify/src/restify.ts | 124 ++++++++++++++++++ packages/plugin-restify/test/restify.test.ts | 2 +- packages/plugin-restify/tsconfig.json | 8 ++ .../plugin-restify/types/bugsnag-restify.d.ts | 23 ---- tsconfig.json | 1 - 10 files changed, 233 insertions(+), 142 deletions(-) create mode 100644 packages/plugin-restify/rollup.config.npm.mjs delete mode 100644 packages/plugin-restify/src/request-info.js create mode 100644 packages/plugin-restify/src/request-info.ts delete mode 100644 packages/plugin-restify/src/restify.js create mode 100644 packages/plugin-restify/src/restify.ts create mode 100644 packages/plugin-restify/tsconfig.json delete mode 100644 packages/plugin-restify/types/bugsnag-restify.d.ts diff --git a/packages/plugin-restify/package.json b/packages/plugin-restify/package.json index 19f22ad447..ee48062d95 100644 --- a/packages/plugin-restify/package.json +++ b/packages/plugin-restify/package.json @@ -1,8 +1,15 @@ { "name": "@bugsnag/plugin-restify", "version": "8.4.0", - "main": "src/restify.js", - "types": "types/bugsnag-restify.d.ts", + "main": "dist/restify.js", + "types": "dist/types/restify.d.ts", + "exports": { + ".": { + "types": "./dist/types/restify.d.ts", + "default": "./dist/restify.js", + "import": "./dist/restify.mjs" + } + }, "description": "@bugsnag/js error handling middleware for Restify web servers", "homepage": "https://www.bugsnag.com/", "repository": { @@ -13,8 +20,7 @@ "access": "public" }, "files": [ - "src", - "types" + "dist" ], "author": "Bugsnag", "license": "MIT", @@ -24,5 +30,11 @@ "devDependencies": { "@bugsnag/core": "^8.4.0", "@types/restify": "^8.4.2" + }, + "scripts": { + "build": "npm run build:npm", + "build:npm": "rollup --config rollup.config.npm.mjs", + "clean": "rm -rf dist/*", + "test:types": "tsc -p tsconfig.json" } } diff --git a/packages/plugin-restify/rollup.config.npm.mjs b/packages/plugin-restify/rollup.config.npm.mjs new file mode 100644 index 0000000000..0b7c473480 --- /dev/null +++ b/packages/plugin-restify/rollup.config.npm.mjs @@ -0,0 +1,6 @@ +import createRollupConfig from "../../.rollup/index.mjs" + +export default createRollupConfig({ + input: "src/restify.ts", + external: ["restify", "async_hooks", "net"], +}) \ No newline at end of file diff --git a/packages/plugin-restify/src/request-info.js b/packages/plugin-restify/src/request-info.js deleted file mode 100644 index c46af8e1e0..0000000000 --- a/packages/plugin-restify/src/request-info.js +++ /dev/null @@ -1,36 +0,0 @@ -const { extractObject } = require('@bugsnag/core') - -module.exports = req => { - const connection = req.connection - const address = connection && connection.address && connection.address() - const portNumber = address && address.port - const path = req.getPath() || req.url - const url = req.absoluteUri(path) - const request = { - url: url, - path, - httpMethod: req.method, - headers: req.headers, - httpVersion: req.httpVersion - } - - request.params = extractObject(req, 'params') - request.query = extractObject(req, 'query') - request.body = extractObject(req, 'body') - - request.clientIp = req.headers['x-forwarded-for'] || (connection ? connection.remoteAddress : undefined) - request.referer = req.headers.referer || req.headers.referrer - - if (connection) { - request.connection = { - remoteAddress: connection.remoteAddress, - remotePort: connection.remotePort, - bytesRead: connection.bytesRead, - bytesWritten: connection.bytesWritten, - localPort: portNumber, - localAddress: address ? address.address : undefined, - IPVersion: address ? address.family : undefined - } - } - return request -} diff --git a/packages/plugin-restify/src/request-info.ts b/packages/plugin-restify/src/request-info.ts new file mode 100644 index 0000000000..b7ab83bb06 --- /dev/null +++ b/packages/plugin-restify/src/request-info.ts @@ -0,0 +1,78 @@ +import { extractObject } from '@bugsnag/core' +import type { AddressInfo } from 'net' +import type { Request } from 'restify' + +export interface RequestInfo extends Omit { + path: string + httpMethod?: string + clientIp?: string + referer?: string + headers?: { [key: string]: string } + connection?: { + remoteAddress?: string + remotePort?: number + bytesRead?: number + bytesWritten?: number + localPort?: number + localAddress?: string + IPVersion?: string + } +} + +export const getFirstHeader = (header: string | string[] | undefined): string | undefined => { + if (Array.isArray(header)) return header[0] + return header +} + +const isAddressInfo = (info: any): info is AddressInfo => { + return info && typeof info === 'object' && 'port' in info && 'address' in info && 'family' in info +} + +const extractRequestInfo = (req: Request): RequestInfo => { + const connection = req.socket || req.connection + const address = connection && connection.address && connection.address() + const portNumber = isAddressInfo(address) ? address.port : undefined + const path = req.getPath() || req.url + const url = req.absoluteUri(path as string) + + // Convert headers to the expected format + const formattedHeaders: { [key: string]: string } = {} + if (req.headers) { + Object.keys(req.headers).forEach(key => { + const value = req.headers[key] + if (value !== undefined) { + formattedHeaders[key] = Array.isArray(value) ? value[0] : value + } + }) + } + + const request: Partial = { + url: url, + path: path as string, + httpMethod: req.method, + headers: formattedHeaders, + httpVersion: req.httpVersion + } + + request.params = extractObject(req, 'params') + request.query = extractObject(req, 'query') + request.body = extractObject(req, 'body') + + request.clientIp = getFirstHeader(req.headers['x-forwarded-for']) || (connection ? connection.remoteAddress : undefined) + request.referer = getFirstHeader(req.headers.referer) || getFirstHeader(req.headers.referrer) + + if (connection) { + request.connection = { + remoteAddress: connection.remoteAddress, + remotePort: connection.remotePort, + bytesRead: connection.bytesRead, + bytesWritten: connection.bytesWritten, + localPort: portNumber, + localAddress: isAddressInfo(address) ? address.address : undefined, + IPVersion: isAddressInfo(address) ? address.family : undefined, + } + } + return request as RequestInfo +} + +export default extractRequestInfo \ No newline at end of file diff --git a/packages/plugin-restify/src/restify.js b/packages/plugin-restify/src/restify.js deleted file mode 100644 index e32333475a..0000000000 --- a/packages/plugin-restify/src/restify.js +++ /dev/null @@ -1,77 +0,0 @@ -const extractRequestInfo = require('./request-info') -const { cloneClient } = require('@bugsnag/core') -const handledState = { - severity: 'error', - unhandled: true, - severityReason: { - type: 'unhandledErrorMiddleware', - attributes: { framework: 'Restify' } - } -} - -module.exports = { - name: 'restify', - load: client => { - const requestHandler = (req, res, next) => { - // clone the client to be scoped to this request. If sessions are enabled, start one - const requestClient = cloneClient(client) - if (requestClient._config.autoTrackSessions) { - requestClient.startSession() - } - - // attach it to the request - req.bugsnag = requestClient - - // extract request info and pass it to the relevant bugsnag properties - requestClient.addOnError((event) => { - const { request, metadata } = getRequestAndMetadataFromReq(req) - event.request = { ...event.request, ...request } - event.addMetadata('request', metadata) - if (event._handledState.severityReason.type === 'unhandledException') { - event._handledState = handledState - } - }, true) - - client._clientContext.run(requestClient, next) - } - - const errorHandler = (req, res, err, cb) => { - if (!client._config.autoDetectErrors) return cb() - if (err.statusCode && err.statusCode < 500) return cb() - - const event = client.Event.create(err, false, handledState, 'restify middleware', 1) - const { metadata, request } = getRequestAndMetadataFromReq(req) - event.request = { ...event.request, ...request } - event.addMetadata('request', metadata) - - if (req.bugsnag) { - req.bugsnag._notify(event) - } else { - client._logger.warn( - 'req.bugsnag is not defined. Make sure the @bugsnag/plugin-restify requestHandler middleware is added first.' - ) - client._notify(event) - } - cb() - } - - return { requestHandler, errorHandler } - } -} - -const getRequestAndMetadataFromReq = req => { - const { body, ...requestInfo } = extractRequestInfo(req) - return { - metadata: requestInfo, - request: { - body, - clientIp: requestInfo.clientIp, - headers: requestInfo.headers, - httpMethod: requestInfo.httpMethod, - url: requestInfo.url, - referer: requestInfo.referer // Not part of the notifier spec for request but leaving for backwards compatibility - } - } -} - -module.exports.default = module.exports diff --git a/packages/plugin-restify/src/restify.ts b/packages/plugin-restify/src/restify.ts new file mode 100644 index 0000000000..f14d0addd8 --- /dev/null +++ b/packages/plugin-restify/src/restify.ts @@ -0,0 +1,124 @@ +import type { Client, Plugin } from '@bugsnag/core' +import { cloneClient } from '@bugsnag/core' +import { AsyncLocalStorage } from 'async_hooks' +import type { Next, Request, Response } from 'restify' +import restify from 'restify' +import type { RequestInfo } from './request-info' +import extractRequestInfo from './request-info' + +declare module 'restify' { + interface Request { + bugsnag?: Client + } +} + +// add a new call signature for the getPlugin() method that types the plugin result +declare module '@bugsnag/core' { + interface Client { + getPlugin(id: 'restify'): BugsnagPluginRestifyResult | undefined + } +} + +interface RestifyError extends Error { + statusCode?: number +} + +interface BugsnagPluginRestifyResult { + requestHandler: restify.RequestHandler + errorHandler: (req: restify.Request, res: restify.Response, err: RestifyError, cb: (...args: any[]) => void) => void +} + +interface ExtractedRequestData { + metadata: Omit + request: { + body: RequestInfo['body'] + clientIp: RequestInfo['clientIp'] + headers: RequestInfo['headers'] + httpMethod: RequestInfo['httpMethod'] + url: RequestInfo['url'] + referer: RequestInfo['referer'] + } +} + +interface InternalClient extends Client { + _clientContext: AsyncLocalStorage +} + +const handledState = { + severity: 'error', + unhandled: true, + severityReason: { + type: 'unhandledErrorMiddleware', + attributes: { framework: 'Restify' } + } +} + +const plugin: Plugin = { + name: 'restify', + load: (client: Client): BugsnagPluginRestifyResult => { + const internalClient = client as InternalClient + + const requestHandler = (req: Request, res: Response, next: Next) => { + // clone the client to be scoped to this request. If sessions are enabled, start one + const requestClient = cloneClient(internalClient) + if (requestClient._config.autoTrackSessions) { + requestClient.startSession() + } + + // attach it to the request + req.bugsnag = requestClient + + // extract request info and pass it to the relevant bugsnag properties + requestClient.addOnError((event) => { + const { request, metadata } = getRequestAndMetadataFromReq(req) + event.request = { ...event.request, ...request } + event.addMetadata('request', metadata) + if (event._handledState.severityReason.type === 'unhandledException') { + // @ts-expect-error override readonly property + event._handledState = handledState + } + }, true); + + internalClient._clientContext.run(requestClient, next) + } + + const errorHandler = (req: Request, res: Response, err: RestifyError, cb: () => void) => { + if (!internalClient._config.autoDetectErrors) return cb() + if (err.statusCode && err.statusCode < 500) return cb() + + const event = internalClient.Event.create(err, false, handledState, 'restify middleware', 1) + const { metadata, request } = getRequestAndMetadataFromReq(req) + event.request = { ...event.request, ...request } + event.addMetadata('request', metadata) + + if (req.bugsnag) { + req.bugsnag._notify(event) + } else { + internalClient._logger.warn( + 'req.bugsnag is not defined. Make sure the @bugsnag/plugin-restify requestHandler middleware is added first.' + ) + internalClient._notify(event) + } + cb() + } + + return { requestHandler, errorHandler } + } +} + +const getRequestAndMetadataFromReq = (req: Request): ExtractedRequestData => { + const { body, ...requestInfo } = extractRequestInfo(req) + return { + metadata: requestInfo, + request: { + body, + clientIp: requestInfo.clientIp, + headers: requestInfo.headers, + httpMethod: requestInfo.httpMethod, + url: requestInfo.url, + referer: requestInfo.referer // Not part of the notifier spec for request but leaving for backwards compatibility + } + } +} + +export default plugin \ No newline at end of file diff --git a/packages/plugin-restify/test/restify.test.ts b/packages/plugin-restify/test/restify.test.ts index 8f5f499456..13bdd1599c 100644 --- a/packages/plugin-restify/test/restify.test.ts +++ b/packages/plugin-restify/test/restify.test.ts @@ -1,4 +1,4 @@ -import { Client } from '@bugsnag/core' +import { Client, Event } from '@bugsnag/core' import plugin from '../src/restify' describe('plugin: restify', () => { diff --git a/packages/plugin-restify/tsconfig.json b/packages/plugin-restify/tsconfig.json new file mode 100644 index 0000000000..66a7db7b94 --- /dev/null +++ b/packages/plugin-restify/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": { + "lib": ["es2017"], + "types": ["node"] + } +} \ No newline at end of file diff --git a/packages/plugin-restify/types/bugsnag-restify.d.ts b/packages/plugin-restify/types/bugsnag-restify.d.ts deleted file mode 100644 index 16542a5c4a..0000000000 --- a/packages/plugin-restify/types/bugsnag-restify.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Client, Plugin } from '@bugsnag/core' -import restify from 'restify' - -declare const bugsnagPluginRestify: Plugin -export default bugsnagPluginRestify - -interface BugsnagPluginRestifyResult { - requestHandler: restify.RequestHandler - errorHandler: (req: restify.Request, res: restify.Response, err: Error, cb: (...args: any[]) => void) => void -} - -// add a new call signature for the getPlugin() method that types the plugin result -declare module '@bugsnag/core' { - interface Client { - getPlugin(id: 'restify'): BugsnagPluginRestifyResult | undefined - } -} - -declare module 'restify' { - interface Request { - bugsnag?: Client - } -} diff --git a/tsconfig.json b/tsconfig.json index d4125e67d2..e5e180748c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,7 +22,6 @@ "packages/plugin-react", "packages/plugin-vue", "packages/plugin-koa", - "packages/plugin-restify", "packages/node", "packages/plugin-interaction-breadcrumbs", "packages/browser" From f8d0eb3c5b084bd80afa5d9f54903d9362927249 Mon Sep 17 00:00:00 2001 From: AnastasiiaSvietlova <119674359+AnastasiiaSvietlova@users.noreply.github.com> Date: Thu, 18 Sep 2025 17:53:38 +0200 Subject: [PATCH 17/17] Convert @bugsnag/plugin-koa to TypeScript (#2550) * convert plugin koa to ts * change connection to socket * update rollup config * update tests * remove unnecessary exports * update rollup configuration to retain generator function * fix some types * change type casting to ts-expect error --------- Co-authored-by: Ben Wilson --- packages/plugin-koa/package.json | 20 ++++-- packages/plugin-koa/rollup.config.npm.mjs | 52 +++++++++++++++ packages/plugin-koa/src/{koa.js => koa.ts} | 66 ++++++++++++++----- packages/plugin-koa/src/request-info.js | 28 --------- packages/plugin-koa/src/request-info.ts | 73 ++++++++++++++++++++++ packages/plugin-koa/test/koa.test.ts | 2 +- packages/plugin-koa/tsconfig.json | 8 +++ packages/plugin-koa/types/bugsnag-koa.d.ts | 23 ------- tsconfig.json | 1 - 9 files changed, 199 insertions(+), 74 deletions(-) create mode 100644 packages/plugin-koa/rollup.config.npm.mjs rename packages/plugin-koa/src/{koa.js => koa.ts} (63%) delete mode 100644 packages/plugin-koa/src/request-info.js create mode 100644 packages/plugin-koa/src/request-info.ts create mode 100644 packages/plugin-koa/tsconfig.json delete mode 100644 packages/plugin-koa/types/bugsnag-koa.d.ts diff --git a/packages/plugin-koa/package.json b/packages/plugin-koa/package.json index 5f033053fe..9e2d2a188c 100644 --- a/packages/plugin-koa/package.json +++ b/packages/plugin-koa/package.json @@ -1,8 +1,15 @@ { "name": "@bugsnag/plugin-koa", "version": "8.4.0", - "main": "src/koa.js", - "types": "types/bugsnag-koa.d.ts", + "main": "dist/koa.js", + "types": "dist/types/koa.d.ts", + "exports": { + ".": { + "types": "./dist/types/koa.d.ts", + "default": "./dist/koa.js", + "import": "./dist/koa.mjs" + } + }, "description": "@bugsnag/js error handling middleware for Koa web servers", "homepage": "https://www.bugsnag.com/", "repository": { @@ -13,8 +20,7 @@ "access": "public" }, "files": [ - "src", - "types" + "dist" ], "author": "Bugsnag", "license": "MIT", @@ -24,5 +30,11 @@ "devDependencies": { "@bugsnag/core": "^8.4.0", "@types/koa": "2.13.4" + }, + "scripts": { + "build": "npm run build:npm", + "build:npm": "rollup --config rollup.config.npm.mjs", + "clean": "rm -rf dist/*", + "test:types": "tsc -p tsconfig.json" } } diff --git a/packages/plugin-koa/rollup.config.npm.mjs b/packages/plugin-koa/rollup.config.npm.mjs new file mode 100644 index 0000000000..64ff8f2c35 --- /dev/null +++ b/packages/plugin-koa/rollup.config.npm.mjs @@ -0,0 +1,52 @@ +import typescript from '@rollup/plugin-typescript' +import replace from '@rollup/plugin-replace' +import fs from 'fs' + +const packageJson = JSON.parse(fs.readFileSync(`${process.cwd()}/package.json`)) + +export default { + input: "src/koa.ts", + output: [ + { + dir: 'dist', + generatedCode: { + preset: 'es2015', + }, + entryFileNames: '[name].js', + format: 'cjs' + }, + { + dir: 'dist', + generatedCode: { + preset: 'es2015', + }, + entryFileNames: '[name].mjs', + format: 'esm' + } + ], + external: ["koa", "async_hooks", "http", "net", "@bugsnag/core"], + plugins: [ + replace({ + preventAssignment: true, + values: { + __VERSION__: packageJson.version, + } + }), + typescript({ + removeComments: true, + noEmitOnError: true, + compilerOptions: { + target: "es2017", // Preserve async/await for Koa compatibility + module: "es2015", + moduleResolution: "bundler", + lib: ["es2017"], + allowJs: true, + strict: true, + esModuleInterop: true, + declaration: true, + declarationMap: true, + declarationDir: 'dist/types', + } + }) + ] +} \ No newline at end of file diff --git a/packages/plugin-koa/src/koa.js b/packages/plugin-koa/src/koa.ts similarity index 63% rename from packages/plugin-koa/src/koa.js rename to packages/plugin-koa/src/koa.ts index 1a2d0733e9..f129c38164 100644 --- a/packages/plugin-koa/src/koa.js +++ b/packages/plugin-koa/src/koa.ts @@ -1,5 +1,34 @@ -const { cloneClient } = require('@bugsnag/core') -const extractRequestInfo = require('./request-info') +import { Client, cloneClient, Plugin } from '@bugsnag/core' +import { AsyncLocalStorage } from 'async_hooks' +import * as Koa from 'koa' +import extractRequestInfo from './request-info' + +interface BugsnagPluginKoaResult { + errorHandler: (err: KoaError, ctx: Koa.Context) => void + requestHandler: Koa.Middleware +} + +// add a new call signature for the getPlugin() method that types the plugin result +declare module '@bugsnag/core' { + interface Client { + getPlugin(id: 'koa'): BugsnagPluginKoaResult | undefined + } +} + +// define ctx.bugsnag for koa middleware by declaration merging +declare module 'koa' { + interface BaseContext { + bugsnag?: Client + } +} + +interface InternalClient extends Client { + _clientContext: AsyncLocalStorage +} + +interface KoaError extends Error { + status?: number +} const handledState = { severity: 'error', @@ -10,12 +39,14 @@ const handledState = { } } -module.exports = { +const plugin: Plugin = { name: 'koa', - load: client => { - const requestHandler = async (ctx, next) => { + load: (client: Client): BugsnagPluginKoaResult => { + const internalClient = client as InternalClient + + const requestHandler = async (ctx: Koa.Context, next: Koa.Next) => { // clone the client to be scoped to this request. If sessions are enabled, start one - const requestClient = cloneClient(client) + const requestClient = cloneClient(internalClient) if (requestClient._config.autoTrackSessions) { requestClient.startSession() } @@ -28,17 +59,18 @@ module.exports = { event.request = { ...event.request, ...request } event.addMetadata('request', metadata) if (event._handledState.severityReason.type === 'unhandledException') { - event.severity = 'error' + event.severity = 'error'; + // @ts-expect-error override readonly property event._handledState = handledState } }, true) - await client._clientContext.run(requestClient, next) + await internalClient._clientContext.run(requestClient, next) } - requestHandler.v1 = function * (next) { + requestHandler.v1 = function * (this: Koa.Context, next: Koa.Next) { // clone the client to be scoped to this request. If sessions are enabled, start one - const requestClient = cloneClient(client) + const requestClient = cloneClient(internalClient) if (requestClient._config.autoTrackSessions) { requestClient.startSession() } @@ -55,20 +87,20 @@ module.exports = { yield next } - const errorHandler = (err, ctx) => { + const errorHandler = (err: KoaError, ctx: Koa.Context) => { // don't notify if "autoDetectErrors" is disabled OR the error was triggered // by ctx.throw with a non 5xx status const shouldNotify = - client._config.autoDetectErrors && + internalClient._config.autoDetectErrors && (err.status === undefined || err.status >= 500) if (shouldNotify) { - const event = client.Event.create(err, false, handledState, 'koa middleware', 1) + const event = internalClient.Event.create(err, false, handledState, 'koa middleware', 1) if (ctx.bugsnag) { ctx.bugsnag._notify(event) } else { - client._logger.warn('ctx.bugsnag is not defined. Make sure the @bugsnag/plugin-koa requestHandler middleware is added first.') + internalClient._logger.warn('ctx.bugsnag is not defined. Make sure the @bugsnag/plugin-koa requestHandler middleware is added first.') // the request metadata should be added by the requestHandler, but as there's // no "ctx.bugsnag" we have to assume the requestHandler has not run @@ -76,7 +108,7 @@ module.exports = { event.request = { ...event.request, ...request } event.addMetadata('request', metadata) - client._notify(event) + internalClient._notify(event) } } @@ -95,7 +127,7 @@ module.exports = { } } -const getRequestAndMetadataFromCtx = ctx => { +const getRequestAndMetadataFromCtx = (ctx: Koa.Context) => { // Exclude new mappings from metaData but keep existing ones to preserve backwards compatibility const { body, ...requestInfo } = extractRequestInfo(ctx) @@ -113,4 +145,4 @@ const getRequestAndMetadataFromCtx = ctx => { } } -module.exports.default = module.exports +export default plugin diff --git a/packages/plugin-koa/src/request-info.js b/packages/plugin-koa/src/request-info.js deleted file mode 100644 index e5521d38f0..0000000000 --- a/packages/plugin-koa/src/request-info.js +++ /dev/null @@ -1,28 +0,0 @@ -module.exports = ctx => { - if (!ctx) return {} - const request = ctx.req - const connection = request.connection - const address = connection && connection.address && connection.address() - const portNumber = address && address.port - const url = `${ctx.request.href}` - return { - url, - path: request.url, - httpMethod: request.method, - headers: request.headers, - httpVersion: request.httpVersion, - query: ctx.request.query, - body: ctx.request.body, - referer: request.headers.referer || request.headers.referrer, - clientIp: ctx.ip || (request.connection ? request.connection.remoteAddress : undefined), - connection: request.connection ? { - remoteAddress: request.connection.remoteAddress, - remotePort: request.connection.remotePort, - bytesRead: request.connection.bytesRead, - bytesWritten: request.connection.bytesWritten, - localPort: portNumber, - localAddress: address ? address.address : undefined, - IPVersion: address ? address.family : undefined - } : undefined - } -} diff --git a/packages/plugin-koa/src/request-info.ts b/packages/plugin-koa/src/request-info.ts new file mode 100644 index 0000000000..56ce31a642 --- /dev/null +++ b/packages/plugin-koa/src/request-info.ts @@ -0,0 +1,73 @@ +import type { IncomingMessage } from 'http' +import type { Context } from 'koa' +import type { AddressInfo } from 'net' + +interface KoaRequest extends Context { + request: Context['request'] & { + body?: any + } + req: IncomingMessage +} + +interface RequestInfo { + url?: string + path?: string + httpMethod?: string + headers?: Record + httpVersion?: string + query?: Record + body?: Record + referer?: string + clientIp?: string + connection?: { + remoteAddress?: string + remotePort?: number + bytesRead?: number + bytesWritten?: number + localPort?: number + localAddress?: string + IPVersion?: string + } +} + +const isAddressInfo = (info: any): info is AddressInfo => { + return info && typeof info === 'object' && 'port' in info && 'address' in info && 'family' in info +} + +const extractRequestInfo = (ctx?: KoaRequest): RequestInfo => { + if (!ctx) return {} + const request = ctx.req + const connection = request.socket || request.connection + const address = connection && connection.address && connection.address() + const portNumber = isAddressInfo(address) ? address.port : undefined + const url = `${ctx.request.href}` + + // Helper to get first value from header (handles string | string[] | undefined) + const getFirstHeader = (header: string | string[] | undefined): string | undefined => { + if (Array.isArray(header)) return header[0] + return header + } + + return { + url, + path: request.url, + httpMethod: request.method, + headers: request.headers, + httpVersion: request.httpVersion, + query: ctx.request.query, + body: ctx.request.body, + referer: getFirstHeader(request.headers.referer) || getFirstHeader(request.headers.referrer), + clientIp: ctx.ip || (request.socket ? request.socket.remoteAddress : undefined), + connection: request.socket ? { + remoteAddress: request.socket.remoteAddress, + remotePort: request.socket.remotePort, + bytesRead: request.socket.bytesRead, + bytesWritten: request.socket.bytesWritten, + localPort: portNumber, + localAddress: isAddressInfo(address) ? address.address : undefined, + IPVersion: isAddressInfo(address) ? address.family : undefined + } : undefined + } +} + +export default extractRequestInfo \ No newline at end of file diff --git a/packages/plugin-koa/test/koa.test.ts b/packages/plugin-koa/test/koa.test.ts index e75e040ded..35e7600c8c 100644 --- a/packages/plugin-koa/test/koa.test.ts +++ b/packages/plugin-koa/test/koa.test.ts @@ -90,7 +90,7 @@ describe('plugin: koa', () => { httpVersion: '1.0', method: 'GET', url: '/xyz', - connection: { + socket: { remoteAddress: '123.456.789.0', remotePort: 9876, bytesRead: 192837645, diff --git a/packages/plugin-koa/tsconfig.json b/packages/plugin-koa/tsconfig.json new file mode 100644 index 0000000000..66a7db7b94 --- /dev/null +++ b/packages/plugin-koa/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": { + "lib": ["es2017"], + "types": ["node"] + } +} \ No newline at end of file diff --git a/packages/plugin-koa/types/bugsnag-koa.d.ts b/packages/plugin-koa/types/bugsnag-koa.d.ts deleted file mode 100644 index 513166ac4b..0000000000 --- a/packages/plugin-koa/types/bugsnag-koa.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Client, Plugin } from '@bugsnag/core' -import * as Koa from 'koa' -declare const bugsnagPluginKoa: Plugin -export default bugsnagPluginKoa - -interface BugsnagPluginKoaResult { - errorHandler: (err: Error, ctx: Koa.Context) => void - requestHandler: Koa.Middleware -} - -// add a new call signature for the getPlugin() method that types the plugin result -declare module '@bugsnag/core' { - interface Client { - getPlugin(id: 'koa'): BugsnagPluginKoaResult | undefined - } -} - -// define ctx.bugsnag for koa middleware by declaration merging -declare module 'koa' { - interface BaseContext { - bugsnag?: Client - } -} diff --git a/tsconfig.json b/tsconfig.json index e5e180748c..e489be1aa5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -21,7 +21,6 @@ "packages/plugin-navigation-breadcrumbs", "packages/plugin-react", "packages/plugin-vue", - "packages/plugin-koa", "packages/node", "packages/plugin-interaction-breadcrumbs", "packages/browser"