diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index 5b12c0e5..4f58bac6 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -56,7 +56,6 @@ jobs: if: matrix.coverage run: | npx lerna bootstrap --hoist - npx lerna run compile npx lerna run testcov npx lerna run reportcov echo test diff --git a/package-lock.json b/package-lock.json index 3aac76a9..51203470 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,21 +5,19 @@ "requires": true, "dependencies": { "@aws-sdk/config-resolver": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.8.0.tgz", - "integrity": "sha512-dtVB+yaT6gEqvzDt/pFS2suESTHb4qMiak3i34emSAcXilLYwOm3avUV/GApc499epQdxv/aRDAupanLVqTA1g==", - "dev": true, + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.12.0.tgz", + "integrity": "sha512-xx4LcuJqgrT3fZ1FY45nIDCTzAh/pWfLM4Bh5rb1V8mT/ROAuSdG+NHYOVSOUOt7RN6X+cbvhZmztya3LxqL8g==", "requires": { - "@aws-sdk/signature-v4": "3.6.1", - "@aws-sdk/types": "3.6.1", + "@aws-sdk/signature-v4": "3.12.0", + "@aws-sdk/types": "3.12.0", "tslib": "^1.8.0" } }, "@aws-sdk/is-array-buffer": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.6.1.tgz", - "integrity": "sha512-qm2iDJmCrxlQE2dsFG+TujPe7jw4DF+4RTrsFMhk/e3lOl3MAzQ6Fc2kXtgeUcVrZVFTL8fQvXE1ByYyI6WbCw==", - "dev": true, + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.12.0.tgz", + "integrity": "sha512-JtrxC2ZinhiL2GIfMoPYkmd7A5ykpYw4Bf4/uMHJ9d3NcFpsT84ipw4eZhclR+mSR9RUYSP0ObgcDLdjW3xm1w==", "requires": { "tslib": "^1.8.0" } @@ -34,24 +32,22 @@ } }, "@aws-sdk/node-config-provider": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.8.0.tgz", - "integrity": "sha512-VBpFquxACQO9MbdOIz35JgwOH+oJ5JwXpEq2faIhK+0zyM0JqLfJNFnnmHaEH9kBVcdOYJihzDgFje3AnYn7PQ==", - "dev": true, + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.12.0.tgz", + "integrity": "sha512-eJAjQ5PN+cwd0AC4QOUjOjrmCAASkCmovDsNndjWmFjNumJkcUvTezAjOC6TLiEop9M1cT0zkhPBEDGjzDnjZQ==", "requires": { - "@aws-sdk/property-provider": "3.8.0", - "@aws-sdk/shared-ini-file-loader": "3.8.0", - "@aws-sdk/types": "3.6.1", + "@aws-sdk/property-provider": "3.12.0", + "@aws-sdk/shared-ini-file-loader": "3.12.0", + "@aws-sdk/types": "3.12.0", "tslib": "^1.8.0" } }, "@aws-sdk/property-provider": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.8.0.tgz", - "integrity": "sha512-9tOvTp6ObNdBgkqxXu5bpEdyzVnStO+aUprTbCH0lUfgCeig4q21xOt6Xsqt616WGtDJCAbMcdCay0XiDLLjAw==", - "dev": true, + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.12.0.tgz", + "integrity": "sha512-4x9S0mtpehp++g+KWx12ZnYa396qCxJXB/n/njppXlWjUz7am527IN24YVTpFoP2CpNo4uZb9Xi8fW6veZSTJg==", "requires": { - "@aws-sdk/types": "3.6.1", + "@aws-sdk/types": "3.12.0", "tslib": "^1.8.0" } }, @@ -61,58 +57,62 @@ "integrity": "sha512-kZ7ZhbrN1f+vrSRkTJvXsu7BlOyZgym058nPA745+1RZ1Rtv4Ax8oknf2RvJyj/1qRUi8LBaAREjzQ3C8tmLBA==" }, "@aws-sdk/shared-ini-file-loader": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.8.0.tgz", - "integrity": "sha512-wjywtEcsYPwB+asK5iWGeox9ZI4ycaxIGRKJTahFo+VUK6mByIEEG/IF7HuQclSSeDFTt9Occ7hQpXpJ97zpdA==", - "dev": true, + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.12.0.tgz", + "integrity": "sha512-vmd0gIZ0bc5hgyEDYufKfMsDKIPHV1ZXc8UzICV3BAsVf1eXhY8j+19OcxqlB+jWtLnnd2L28XslfRCYK9gduw==", "requires": { "tslib": "^1.8.0" } }, "@aws-sdk/signature-v4": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.6.1.tgz", - "integrity": "sha512-EAR0qGVL4AgzodZv4t+BSuBfyOXhTNxDxom50IFI1MqidR9vI6avNZKcPHhgXbm7XVcsDGThZKbzQ2q7MZ2NTA==", - "dev": true, - "requires": { - "@aws-sdk/is-array-buffer": "3.6.1", - "@aws-sdk/types": "3.6.1", - "@aws-sdk/util-hex-encoding": "3.6.1", - "@aws-sdk/util-uri-escape": "3.6.1", + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.12.0.tgz", + "integrity": "sha512-11ZwHj8GjzsQNmebAaxhFcqSOgK6+5fUcrUDRu+R9HMvdKIuiLpawqCZELupbg4uqhka953rAldjbHjYhUaLuw==", + "requires": { + "@aws-sdk/is-array-buffer": "3.12.0", + "@aws-sdk/types": "3.12.0", + "@aws-sdk/util-hex-encoding": "3.12.0", + "@aws-sdk/util-uri-escape": "3.12.0", "tslib": "^1.8.0" } }, "@aws-sdk/smithy-client": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.6.1.tgz", - "integrity": "sha512-AVpRK4/iUxNeDdAm8UqP0ZgtgJMQeWcagTylijwelhWXyXzHUReY1sgILsWcdWnoy6gq845W7K2VBhBleni8+w==", - "dev": true, + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.12.0.tgz", + "integrity": "sha512-bAPUYEP7UeuECSRVpo3Il09uWO2tE931zQm2ZL446Vv0GJtayYWtX4ZwB7V5ADHtTeCsRtjOcUmnNXJ5M0hGSQ==", "requires": { - "@aws-sdk/middleware-stack": "3.6.1", - "@aws-sdk/types": "3.6.1", + "@aws-sdk/middleware-stack": "3.12.0", + "@aws-sdk/types": "3.12.0", "tslib": "^1.8.0" + }, + "dependencies": { + "@aws-sdk/middleware-stack": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.12.0.tgz", + "integrity": "sha512-X4TmWGLzY8ma99HQ+9vL4PoykfPtxdZ7QK/ZZ51I+i2vCKLz8tlml6y5rVR31TavJrg8qeAp+mQwttniSjmxYQ==", + "requires": { + "tslib": "^1.8.0" + } + } } }, "@aws-sdk/types": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.6.1.tgz", - "integrity": "sha512-4Dx3eRTrUHLxhFdLJL8zdNGzVsJfAxtxPYYGmIddUkO2Gj3WA1TGjdfG4XN/ClI6e1XonCHafQX3UYO/mgnH3g==", - "dev": true + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.12.0.tgz", + "integrity": "sha512-7vnVBV0IdNQ+yyCQFkyLkRohvr7PHj//nGcth9RXG+VmQfp4+8CgBlMuXoeEWvDntrRgdh5lzDO0CliVRquxkw==" }, "@aws-sdk/util-hex-encoding": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.6.1.tgz", - "integrity": "sha512-pzsGOHtU2eGca4NJgFg94lLaeXDOg8pcS9sVt4f9LmtUGbrqRveeyBv0XlkHeZW2n0IZBssPHipVYQFlk7iaRA==", - "dev": true, + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.12.0.tgz", + "integrity": "sha512-hXzhCmPU8Q2U8QkSmMtPhT1sUtXbeFrEtFPyTbWr9p7AccWM3cOCZilOcUtV04cx9RgKNyhY/O1NOdByvSY1lQ==", "requires": { "tslib": "^1.8.0" } }, "@aws-sdk/util-uri-escape": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.6.1.tgz", - "integrity": "sha512-tgABiT71r0ScRJZ1pMX0xO0QPMMiISCtumph50IU5VDyZWYgeIxqkMhIcrL1lX0QbNCMgX0n6rZxGrrbjDNavA==", - "dev": true, + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.12.0.tgz", + "integrity": "sha512-ZkiGtqsE+Krr4ARweq/AV7llrEqLDMR3/R9gvwDcurYSBt1V1hNGTdGNUCSKeKmmeMxneAZXmp+xM3FYZoIjIw==", "requires": { "tslib": "^1.8.0" } @@ -3244,11 +3244,22 @@ "aws-xray-sdk-core": { "version": "file:packages/core", "requires": { + "@aws-sdk/config-resolver": "^3.4.1", + "@aws-sdk/node-config-provider": "^3.4.1", "@aws-sdk/service-error-classification": "^3.4.1", - "@types/cls-hooked": "^4.2.2", + "@aws-sdk/smithy-client": "^3.4.1", + "@aws-sdk/types": "3.6.1", + "@types/cls-hooked": "^4.3.3", "atomic-batcher": "^1.0.2", "cls-hooked": "^4.2.2", "semver": "^5.3.0" + }, + "dependencies": { + "@aws-sdk/types": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.6.1.tgz", + "integrity": "sha512-4Dx3eRTrUHLxhFdLJL8zdNGzVsJfAxtxPYYGmIddUkO2Gj3WA1TGjdfG4XN/ClI6e1XonCHafQX3UYO/mgnH3g==" + } } }, "aws-xray-sdk-express": { @@ -3782,12 +3793,6 @@ "pump": "^3.0.0" } }, - "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "dev": true - }, "lowercase-keys": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", @@ -4343,12 +4348,6 @@ "is-obj": "^2.0.0" } }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true - }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -5328,18 +5327,18 @@ }, "dependencies": { "ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", - "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, "requires": { - "type-fest": "^0.11.0" + "type-fest": "^0.21.3" } }, "type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", - "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true } } @@ -5516,9 +5515,9 @@ "dev": true }, "eslint-rule-docs": { - "version": "1.1.221", - "resolved": "https://registry.npmjs.org/eslint-rule-docs/-/eslint-rule-docs-1.1.221.tgz", - "integrity": "sha512-9vxNL90AmYii4Wy99MLQ3KfGyyfDixLurp9NlxB6tF3tqatL8YuAvjhm6vxRXKEEeMUh5Jc7lT49kiOWY/FhSQ==", + "version": "1.1.226", + "resolved": "https://registry.npmjs.org/eslint-rule-docs/-/eslint-rule-docs-1.1.226.tgz", + "integrity": "sha512-Wnn0ETzE2v2UT0OdRCcdMNPkQtbzyZr3pPPXnkreP0l6ZJaKqnl88dL1DqZ6nCCZZwDGBAnN0Y+nCvGxxLPQLQ==", "dev": true }, "eslint-scope": { @@ -7601,9 +7600,9 @@ "dev": true }, "irregular-plurals": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.2.0.tgz", - "integrity": "sha512-YqTdPLfwP7YFN0SsD3QUVCkm9ZG2VzOXv3DOrw5G5mkMbVwptTwVcFv7/C0vOpBmgTxAeTG19XpUs1E522LW9Q==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.3.0.tgz", + "integrity": "sha512-MVBLKUTangM3EfRPFROhmWQQKRDsrgI83J8GS3jXy+OwYqiR2/aoWndYQ5416jLE3uaGgLH7ncme3X9y09gZ3g==", "dev": true }, "is-absolute": { @@ -7820,9 +7819,9 @@ "dev": true }, "is-path-inside": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz", - "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true }, "is-plain-obj": { @@ -12621,9 +12620,9 @@ } }, "supports-hyperlinks": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz", - "integrity": "sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", "dev": true, "requires": { "has-flag": "^4.0.0", @@ -12995,9 +12994,9 @@ } }, "tsd": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/tsd/-/tsd-0.13.1.tgz", - "integrity": "sha512-+UYM8LRG/M4H8ISTg2ow8SWi65PS7Os+4DUnyiQLbJysXBp2DEmws9SMgBH+m8zHcJZqUJQ+mtDWJXP1IAvB2A==", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/tsd/-/tsd-0.15.1.tgz", + "integrity": "sha512-8ADO2rPntfNiJV4KiqJiiiitfkXLxCbKEFN672JgwNiaEIuiyurTc1+w3InZ+0DqBz73B6Z3UflZcNGw5xMaDA==", "dev": true, "requires": { "eslint-formatter-pretty": "^4.0.0", @@ -13008,59 +13007,6 @@ "update-notifier": "^4.1.0" }, "dependencies": { - "@nodelib/fs.stat": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", - "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", - "dev": true - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "fast-glob": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", - "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", - "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, "find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -13071,32 +13017,6 @@ "path-exists": "^4.0.0" } }, - "globby": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz", - "integrity": "sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - } - }, - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -13125,16 +13045,6 @@ "yargs-parser": "^18.1.3" } }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, "p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -13177,12 +13087,6 @@ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, "read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -13222,21 +13126,6 @@ } } }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, "type-fest": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", @@ -13258,8 +13147,7 @@ "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "tsscmp": { "version": "1.0.6", diff --git a/package.json b/package.json index c7858f32..d17ffa8b 100644 --- a/package.json +++ b/package.json @@ -4,11 +4,7 @@ "private": true, "license": "Apache-2.0", "devDependencies": { - "@aws-sdk/config-resolver": "^3.3.0", "@aws-sdk/middleware-stack": "^3.3.0", - "@aws-sdk/node-config-provider": "^3.3.0", - "@aws-sdk/smithy-client": "^3.3.0", - "@aws-sdk/types": "^3.3.0", "@hapi/hapi": "^20.0.0", "@types/chai": "^4.2.12", "@types/koa": "^2.11.3", @@ -45,7 +41,7 @@ "rewire": "^4.0.1", "sinon": "^9.0.2", "sinon-chai": "^3.5.0", - "tsd": "^0.13.1", + "tsd": "^0.15.1", "typescript": "^4.1.3", "upath": "^1.2.0" }, diff --git a/packages/core/lib/aws-xray.d.ts b/packages/core/lib/aws-xray.d.ts index c517d94d..bdba9865 100644 --- a/packages/core/lib/aws-xray.d.ts +++ b/packages/core/lib/aws-xray.d.ts @@ -39,7 +39,7 @@ export { captureAsyncFunc, captureCallbackFunc, captureFunc } from './capture' export { captureAWS, captureAWSClient } from './patchers/aws_p'; -export type { captureAWSClient as captureAWSv3Client } from './patchers/aws3_p'; +export { captureAWSClient as captureAWSv3Client } from './patchers/aws3_p'; export { captureHTTPs, captureHTTPsGlobal } from './patchers/http_p'; diff --git a/packages/core/lib/patchers/aws3_p.d.ts b/packages/core/lib/patchers/aws3_p.d.ts index 68d186af..304abbb0 100644 --- a/packages/core/lib/patchers/aws3_p.d.ts +++ b/packages/core/lib/patchers/aws3_p.d.ts @@ -1,8 +1,11 @@ -import type { MetadataBearer, Client } from '@aws-sdk/types'; -import type { RegionInputConfig } from '@aws-sdk/config-resolver'; +import { Client, MetadataBearer } from '@aws-sdk/types'; +import { RegionResolvedConfig } from '@aws-sdk/config-resolver'; import { SegmentLike } from '../aws-xray'; -declare type DefaultConfiguration = RegionInputConfig & { - serviceId: string; -}; -export declare function captureAWSClient(client: Client, manualSegment?: SegmentLike): Client; -export {}; +/** + * Instruments AWS SDK V3 clients with X-Ray via middleware. + * + * @param client - AWS SDK V3 client to instrument + * @param manualSegment - Parent segment or subsegment that is passed in for manual mode users + * @returns - the client with the X-Ray instrumentation middleware added to its middleware stack + */ +export declare function captureAWSClient(client: Client, manualSegment?: SegmentLike): Client; diff --git a/packages/core/lib/patchers/aws3_p.js b/packages/core/lib/patchers/aws3_p.js deleted file mode 100644 index 69d2fde0..00000000 --- a/packages/core/lib/patchers/aws3_p.js +++ /dev/null @@ -1,113 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.captureAWSClient = void 0; -const service_error_classification_1 = require("@aws-sdk/service-error-classification"); -const aws_1 = __importDefault(require("../segments/attributes/aws")); -const querystring_1 = require("querystring"); -const subsegment_1 = __importDefault(require("../segments/attributes/subsegment")); -var contextUtils = require('../context_utils'); -var logger = require('../logger'); -const utils_1 = require("../utils"); -async function buildAttributesFromMetadata(client, command, metadata) { - const { extendedRequestId, requestId, httpStatusCode: statusCode, attempts } = metadata; - const serviceIdentifier = client.config.serviceId; - let operation = command.constructor.name.slice(0, -7); - const aws = new aws_1.default({ - extendedRequestId, - requestId, - retryCount: attempts, - request: { - operation, - httpRequest: { - region: await client.config.region(), - statusCode, - }, - params: command.input, - }, - }, serviceIdentifier); - const http = { response: { status: statusCode || 0 } }; - return [aws, http]; -} -function addFlags(http, subsegment, err) { - var _a, _b; - if (err && service_error_classification_1.isThrottlingError(err)) { - subsegment.addThrottleFlag(); - } - else if (((_a = http.response) === null || _a === void 0 ? void 0 : _a.status) === 429) { - subsegment.addThrottleFlag(); - } - const cause = utils_1.getCauseTypeFromHttpStatus((_b = http.response) === null || _b === void 0 ? void 0 : _b.status); - if (cause === 'fault') { - subsegment.addFaultFlag(); - } - else if (cause === 'error') { - subsegment.addErrorFlag(); - } -} -function captureAWSClient(client, manualSegment) { - // create local copy so that we can later call it - const send = client.send; - const serviceIdentifier = client.config.serviceId; - client.send = async (...args) => { - const [command] = args; - const segment = manualSegment || contextUtils.resolveSegment(); - let operation = command.constructor.name.slice(0, -7); - if (!segment) { - const output = serviceIdentifier + '.' + operation; - if (!contextUtils.isAutomaticMode()) { - logger.getLogger().info('Call ' + output + ' requires a segment object' + - ' on the request params as "XRaySegment" for tracing in manual mode. Ignoring.'); - } - else { - logger.getLogger().info('Call ' + output + - ' is missing the sub/segment context for automatic mode. Ignoring.'); - } - return send.apply(client, args); - } - const subsegment = segment.addNewSubsegment(serviceIdentifier); - subsegment.addAttribute('namespace', 'aws'); - try { - const res = (await send.apply(client, [command])); - if (!res) - throw new Error('Failed to get response from instrumented AWS Client.'); - const [aws, http] = await buildAttributesFromMetadata(client, command, res.$metadata); - subsegment.addAttribute('aws', aws); - subsegment.addAttribute('http', http); - addFlags(http, subsegment); - subsegment.close(); - return res; - } - catch (err) { - if (err.$metadata) { - const [aws, http] = await buildAttributesFromMetadata(client, command, err.$metadata); - subsegment.addAttribute('aws', aws); - subsegment.addAttribute('http', http); - addFlags(http, subsegment, err); - } - const errObj = { message: err.message, name: err.name, stack: err.stack || new Error().stack }; - subsegment.close(errObj, true); - throw err; - } - }; - client.middlewareStack.add((next) => async (args) => { - const segment = manualSegment || contextUtils.resolveSegment(); - if (!segment) - return next(args); - const parent = (segment instanceof subsegment_1.default - ? segment.segment - : segment); - args.request.headers['X-Amzn-Trace-Id'] = querystring_1.stringify({ - Root: parent.trace_id, - Parent: segment.id, - Sampled: parent.notTraced ? '0' : '1', - }, ';'); - return next(args); - }, { - step: 'build', - }); - return client; -} -exports.captureAWSClient = captureAWSClient; diff --git a/packages/core/lib/patchers/aws3_p.ts b/packages/core/lib/patchers/aws3_p.ts index 19e377e1..dc240bd5 100644 --- a/packages/core/lib/patchers/aws3_p.ts +++ b/packages/core/lib/patchers/aws3_p.ts @@ -1,10 +1,13 @@ -import type { - MetadataBearer, - ResponseMetadata, +import { + Pluggable, Client, + MetadataBearer, + BuildMiddleware, + MiddlewareStack, + BuildHandlerOptions, } from '@aws-sdk/types'; -import type { RegionInputConfig } from '@aws-sdk/config-resolver'; +import { RegionResolvedConfig } from '@aws-sdk/config-resolver'; import { isThrottlingError } from '@aws-sdk/service-error-classification'; @@ -14,25 +17,33 @@ import { stringify } from 'querystring'; import Subsegment from '../segments/attributes/subsegment'; -var contextUtils = require('../context_utils'); +const contextUtils = require('../context_utils'); + +const logger = require('../logger'); -var logger = require('../logger'); +const { safeParseInt } = require('../utils'); import { getCauseTypeFromHttpStatus } from '../utils'; import { SdkError } from '@aws-sdk/smithy-client'; import { SegmentLike } from '../aws-xray'; -type HttpResponse = { response: { status: number } }; +const XRAY_PLUGIN_NAME: string = 'XRaySDKInstrumentation'; -async function buildAttributesFromMetadata( - client: any, - command: any, - metadata: ResponseMetadata, -): Promise<[ServiceSegment, HttpResponse]> { - const { extendedRequestId, requestId, httpStatusCode: statusCode, attempts } = metadata; - const serviceIdentifier = client.config.serviceId as string; +interface HttpResponse { + response?: { + status?: number, + content_length?: number + } +}; - let operation: string = command.constructor.name.slice(0, -7); +const buildAttributesFromMetadata = async ( + service: string, + operation: string, + region: string, + res: any | null, + error: SdkError | null, +): Promise<[ServiceSegment, HttpResponse]> => { + const { extendedRequestId, requestId, httpStatusCode: statusCode, attempts } = res?.output?.$metadata || error?.$metadata; const aws = new ServiceSegment( { @@ -42,16 +53,26 @@ async function buildAttributesFromMetadata( request: { operation, httpRequest: { - region: await client.config.region(), + region, statusCode, }, - params: command.input, }, }, - serviceIdentifier, + service, ); - const http = { response: { status: statusCode || 0 } }; + const http: HttpResponse = {}; + + if (statusCode) { + http.response = {}; + http.response.status = statusCode; + } + if (res?.response?.headers && res?.response?.headers['content-length'] !== undefined) { + if (!http.response) { + http.response = {}; + } + http.response.content_length = safeParseInt(res.response.headers['content-length']); + } return [aws, http]; } @@ -62,110 +83,111 @@ function addFlags(http: HttpResponse, subsegment: Subsegment, err?: SdkError): v subsegment.addThrottleFlag(); } - const cause = getCauseTypeFromHttpStatus(http.response?.status); + const cause = getCauseTypeFromHttpStatus(safeParseInt(http.response?.status)); if (cause === 'fault') { subsegment.addFaultFlag(); } else if (cause === 'error') { subsegment.addErrorFlag(); } -} - -type DefaultConfiguration = RegionInputConfig & { - serviceId: string; }; -export function captureAWSClient< - Input extends object, - Output extends MetadataBearer, - Configuration extends DefaultConfiguration ->(client: Client, manualSegment?: SegmentLike): Client { - // create local copy so that we can later call it - const send = client.send; - - const serviceIdentifier = client.config.serviceId; - - client.send = async (...args: Parameters): Promise => { - const [command] = args; - const segment = manualSegment || contextUtils.resolveSegment(); - - let operation: string = command.constructor.name.slice(0, -7); - - if (!segment) { - const output = serviceIdentifier + '.' + operation; - - if (!contextUtils.isAutomaticMode()) { - logger.getLogger().info('Call ' + output + ' requires a segment object' + - ' on the request params as "XRaySegment" for tracing in manual mode. Ignoring.'); - } else { - logger.getLogger().info('Call ' + output + - ' is missing the sub/segment context for automatic mode. Ignoring.'); - } - return send.apply(client, args) as Promise; +const getXRayMiddleware = (config: RegionResolvedConfig, manualSegment?: SegmentLike): BuildMiddleware => (next: any, context: any) => async (args: any) => { + const segment = contextUtils.isAutomaticMode() ? contextUtils.resolveSegment() : manualSegment; + const {clientName, commandName} = context; + const operation: string = commandName.slice(0, -7); // Strip trailing "Command" string + const service: string = clientName.slice(0, -6); // Strip trailing "Client" string + + if (!segment) { + const output = service + '.' + operation.charAt(0).toLowerCase() + operation.slice(1); + + if (!contextUtils.isAutomaticMode()) { + logger.getLogger().info('Call ' + output + ' requires a segment object' + + ' passed to captureAWSv3Client for tracing in manual mode. Ignoring.'); + } else { + logger.getLogger().info('Call ' + output + + ' is missing the sub/segment context for automatic mode. Ignoring.'); } + return next(args); + } - const subsegment = segment.addNewSubsegment(serviceIdentifier); - subsegment.addAttribute('namespace', 'aws'); - - try { - const res = (await send.apply(client, [command])) as Output; + const subsegment: Subsegment = segment.addNewSubsegment(service); + subsegment.addAttribute('namespace', 'aws'); + const parent = (segment instanceof Subsegment ? segment.segment : segment); - if (!res) throw new Error('Failed to get response from instrumented AWS Client.'); + args.request.headers['X-Amzn-Trace-Id'] = stringify( + { + Root: parent.trace_id, + Parent: subsegment.id, + Sampled: parent.notTraced ? '0' : '1', + }, + ';', + ); + let res; + try { + res = await next(args); + if (!res) throw new Error('Failed to get response from instrumented AWS Client.'); + + const [aws, http] = await buildAttributesFromMetadata( + service, + operation, + await config.region(), + res, + null, + ); + + subsegment.addAttribute('aws', aws); + subsegment.addAttribute('http', http); + + addFlags(http, subsegment); + subsegment.close(); + return res; + } catch (err) { + if (err.$metadata) { const [aws, http] = await buildAttributesFromMetadata( - client, - command, - res.$metadata, + service, + operation, + await config.region(), + null, + err, ); subsegment.addAttribute('aws', aws); subsegment.addAttribute('http', http); - - addFlags(http, subsegment); - subsegment.close(); - return res; - } catch (err) { - if (err.$metadata) { - const [aws, http] = await buildAttributesFromMetadata( - client, - command, - err.$metadata, - ); - - subsegment.addAttribute('aws', aws); - subsegment.addAttribute('http', http); - addFlags(http, subsegment, err); - } - - const errObj = { message: err.message, name: err.name, stack: err.stack || new Error().stack }; - - subsegment.close(errObj, true); - throw err; + addFlags(http, subsegment, err); } - }; - - client.middlewareStack.add( - (next) => async (args: any) => { - const segment = manualSegment || contextUtils.resolveSegment(); - if (!segment) return next(args); - - const parent = (segment instanceof Subsegment - ? segment.segment - : segment); - - args.request.headers['X-Amzn-Trace-Id'] = stringify( - { - Root: parent.trace_id, - Parent: segment.id, - Sampled: parent.notTraced ? '0' : '1', - }, - ';', - ); - return next(args); - }, - { - step: 'build', - }, - ); + const errObj = { message: err.message, name: err.name, stack: err.stack || new Error().stack }; + subsegment.close(errObj, true); + throw err; + } +}; + +const xRayMiddlewareOptions: BuildHandlerOptions = { + name: XRAY_PLUGIN_NAME, + step: 'build', +}; + +const getXRayPlugin = (config: RegionResolvedConfig, manualSegment?: SegmentLike): Pluggable => ({ + applyToStack: (stack: MiddlewareStack) => { + stack.add(getXRayMiddleware(config, manualSegment), xRayMiddlewareOptions); + }, +}); + +/** + * Instruments AWS SDK V3 clients with X-Ray via middleware. + * + * @param client - AWS SDK V3 client to instrument + * @param manualSegment - Parent segment or subsegment that is passed in for manual mode users + * @returns - the client with the X-Ray instrumentation middleware added to its middleware stack + */ +export function captureAWSClient< + Input extends object, + Output extends MetadataBearer, + Configuration extends RegionResolvedConfig, +> (client: Client, manualSegment?: SegmentLike): Client { + // Remove existing middleware to ensure operation is idempotent + client.middlewareStack.remove(XRAY_PLUGIN_NAME); + client.middlewareStack.use(getXRayPlugin(client.config, manualSegment)); return client; } diff --git a/packages/core/lib/segments/attributes/aws.js b/packages/core/lib/segments/attributes/aws.js index 66f071f4..be463337 100644 --- a/packages/core/lib/segments/attributes/aws.js +++ b/packages/core/lib/segments/attributes/aws.js @@ -19,11 +19,15 @@ function Aws(res, serviceName) { Aws.prototype.init = function init(res, serviceName) { //TODO: account ID this.operation = formatOperation(res.request.operation) || ''; - this.region = res.request.httpRequest.region || ''; - this.request_id = res.requestId || ''; + if (res && res.request && res.request.httpRequest && res.request.httpRequest.region) { + this.region = res.request.httpRequest.region; + } + if (res && res.requestId) { + this.request_id = res.requestId; + } this.retries = res.retryCount || 0; - if (res.extendedRequestId && serviceName === 's3') + if (res.extendedRequestId && serviceName && serviceName.toLowerCase() === 's3') this.id_2 = res.extendedRequestId; this.addData(capturer.capture(serviceName, res)); diff --git a/packages/core/package.json b/packages/core/package.json index 0000bee9..df178704 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -24,7 +24,11 @@ "//": "@types/cls-hooked is exposed in API so must be in dependencies, not devDependencies", "dependencies": { "@aws-sdk/service-error-classification": "^3.4.1", - "@types/cls-hooked": "^4.2.2", + "@aws-sdk/node-config-provider": "^3.4.1", + "@aws-sdk/config-resolver": "^3.4.1", + "@aws-sdk/smithy-client": "^3.4.1", + "@aws-sdk/types": "^3.4.1", + "@types/cls-hooked": "^4.3.3", "atomic-batcher": "^1.0.2", "cls-hooked": "^4.2.2", "semver": "^5.3.0" @@ -34,9 +38,9 @@ "compile": "tsc && npm run copy-lib && npm run copy-test", "copy-lib": "find lib -type f \\( -name '*.d.ts' -o -name '*.json' \\) | xargs -I % ../../scripts/cp-with-structure.sh % dist", "copy-test": "find test -name '*.json' | xargs -I % ../../scripts/cp-with-structure.sh % dist", - "test": "mocha --recursive ./dist/test/ -R spec && tsd && mocha --recursive ./dist/test_async/ -R spec", + "test": "npm run compile && mocha --recursive ./dist/test/ -R spec && tsd && mocha --recursive ./dist/test_async/ -R spec", "test-d": "tsd", - "test-async": "mocha --recursive ./dist/test_async/ -R spec", + "test-async": "npm run compile && mocha --recursive ./dist/test_async/ -R spec", "clean": "rm -rf dist && rm -rf node_modules", "testcov": "nyc npm run test", "reportcov": "nyc report --reporter=text-lcov > coverage.lcov && codecov" diff --git a/packages/core/test/unit/patchers/aws3_p.test.js b/packages/core/test/unit/patchers/aws3_p.test.js index d7c6bac5..fe953530 100644 --- a/packages/core/test/unit/patchers/aws3_p.test.js +++ b/packages/core/test/unit/patchers/aws3_p.test.js @@ -20,7 +20,7 @@ var traceId = '1-57fbe041-2c7ad569f5d6ff149137be86'; describe('AWS v3 patcher', function() { describe('#captureAWSClient', function() { - var customStub, sandbox, addMiddleware; + var customStub, sandbox, useMiddleware; var awsClient = { send: function() {}, @@ -33,44 +33,48 @@ describe('AWS v3 patcher', function() { beforeEach(function() { sandbox = sinon.createSandbox(); customStub = sandbox.stub(awsClient, 'send'); - addMiddleware = sandbox.stub(awsClient.middlewareStack, 'add'); + useMiddleware = sandbox.stub(awsClient.middlewareStack, 'use'); }); afterEach(function() { sandbox.restore(); }); - it('should call middlewareStack.add and return the service', function() { - var patched = awsPatcher.captureAWSClient(awsClient); - addMiddleware.should.have.been.calledOnce; + it('should call middlewareStack.use and return the service', function() { + const patched = awsPatcher.captureAWSClient(awsClient); + useMiddleware.should.have.been.calledOnce; assert.equal(patched, awsClient); }); }); describe('#captureAWSRequest', function() { - var awsClient, awsRequest, sandbox, segment, stubResolve, stubResolveManual, addNewSubsegmentStub, sub; + var awsClient, awsRequest, sandbox, segment, stubResolve, addNewSubsegmentStub, sub; before(function() { awsClient = { send: async (req) => { - const handler = awsClient.middlewareStack.resolve((args) => args); + const context = { + clientName: 'S3Client', + commandName: 'ListBucketsCommand', + }; + const handler = awsClient.middlewareStack.resolve((args) => { + const error = req.response.error; + if (error) { + const err = new Error(error.message); + err.name = error.code; + err.$metadata = req.response.$metadata; + throw err; + } + return args; + }, context); await handler(req); - const error = req.response.error; - if (error) { - const err = new Error(error.message); - err.name = error.code; - err.$metadata = req.response.$metadata; - throw err; - } return req.response; }, config: { - serviceId: 's3', region: async () => 'us-east-1', }, middlewareStack: constructStack(), }; - awsClient = awsPatcher.captureAWSClient(awsClient); }); beforeEach(function() { @@ -86,16 +90,18 @@ describe('AWS v3 patcher', function() { }, headers: {} }; - this.response = { - $metadata: {} + this.response = {}; + this.output = { + $metadata: { + requestId: '123', + extendedRequestId: '456', + } }; } })(); segment = new Segment('testSegment', traceId); sub = segment.addNewSubsegment('subseg'); - - stubResolveManual = sandbox.stub(contextUtils, 'resolveManualSegmentParams'); stubResolve = sandbox.stub(contextUtils, 'resolveSegment').returns(segment); addNewSubsegmentStub = sandbox.stub(segment, 'addNewSubsegment').returns(sub); }); @@ -104,111 +110,142 @@ describe('AWS v3 patcher', function() { sandbox.restore(); }); - it.skip('should call to resolve any manual params', function() { - awsClient.send(awsRequest); + describe('#automaticMode', () => { + beforeEach(() => { + sandbox.stub(contextUtils, 'isAutomaticMode').returns(true); + }); - stubResolveManual.should.have.been.calledWith(awsRequest.params); - }); + before(() => { + awsClient = awsPatcher.captureAWSClient(awsClient); + }); - it('should log an info statement and exit if parent is not found on the context or on the call params', function(done) { - stubResolve.returns(); - var logStub = sandbox.stub(logger, 'info'); + it('should log an info statement and exit if parent is not found in the context for automatic mode', (done) => { + stubResolve.returns(); + const logStub = sandbox.stub(logger, 'info'); - awsClient.send(awsRequest); + awsClient.send(awsRequest); - setTimeout(function() { - logStub.should.have.been.calledOnce; - done(); - }, 50); - }); + setTimeout(function() { + logStub.should.have.been.calledOnce; + done(); + }, 50); + }); - it('should inject the tracing headers', async function() { - sandbox.stub(contextUtils, 'isAutomaticMode').returns(true); + it('should inject the tracing headers', async function() { + await awsClient.send(awsRequest); - awsClient.middlewareStack.add((next) => (args) => { - stubResolve.returns(sub); - next(args); - stubResolve.returns(segment); - }, { step: 'build', priority: 'high' }); + assert.isTrue(addNewSubsegmentStub.calledWith('S3')); - await awsClient.send(awsRequest); + const expected = new RegExp('^Root=' + traceId + ';Parent=' + sub.id + ';Sampled=1$'); + assert.match(awsRequest.request.headers['X-Amzn-Trace-Id'], expected); + }); - assert.isTrue(addNewSubsegmentStub.calledWith('s3')); + it('should close on complete with no errors when code 200 is seen', async function() { + const closeStub = sandbox.stub(sub, 'close').returns(); + sandbox.stub(sub, 'addAttribute').returns(); + sandbox.stub(Aws.prototype, 'init').returns(); - var expected = new RegExp('^Root=' + traceId + ';Parent=' + sub.id + ';Sampled=1$'); - assert.match(awsRequest.request.headers['X-Amzn-Trace-Id'], expected); - }); + awsRequest.response = { + $metadata: { httpStatusCode: 200 }, + }; - it('should close on complete with no errors when code 200 is seen', async function() { - var closeStub = sandbox.stub(sub, 'close').returns(); - sandbox.stub(contextUtils, 'isAutomaticMode').returns(true); - sandbox.stub(sub, 'addAttribute').returns(); - sandbox.stub(Aws.prototype, 'init').returns(); + await awsClient.send(awsRequest); - awsRequest.response = { - $metadata: { httpStatusCode: 200 }, - }; + closeStub.should.have.been.calledWithExactly(); + }); - await awsClient.send(awsRequest); + it('should mark the subsegment as throttled and error if code 429 is seen', async function() { + const throttleStub = sandbox.stub(sub, 'addThrottleFlag').returns(); - closeStub.should.have.been.calledWithExactly(); - }); + sandbox.stub(sub, 'addAttribute').returns(); + sandbox.stub(Aws.prototype, 'init').returns(); - it('should mark the subsegment as throttled and error if code 429 is seen', async function() { - var throttleStub = sandbox.stub(sub, 'addThrottleFlag').returns(); + awsRequest.response = { + error: { message: 'throttling', code: 'ThrottlingError' }, + $metadata: { httpStatusCode: 429 }, + }; - sandbox.stub(contextUtils, 'isAutomaticMode').returns(true); - sandbox.stub(sub, 'addAttribute').returns(); - sandbox.stub(Aws.prototype, 'init').returns(); + await awsClient.send(awsRequest).catch(() => null); - awsRequest.response = { - error: { message: 'throttling', code: 'ThrottlingError' }, - $metadata: { httpStatusCode: 429 }, - }; + throttleStub.should.have.been.calledOnce; + assert.isTrue(sub.error); + }); - await awsClient.send(awsRequest).catch(() => null); + it('should mark the subsegment as throttled and error if code service.throttledError returns true, regardless of status code', async function() { + const throttleStub = sandbox.stub(sub, 'addThrottleFlag').returns(); - throttleStub.should.have.been.calledOnce; - assert.isTrue(sub.error); - }); + sandbox.stub(sub, 'addAttribute').returns(); + sandbox.stub(Aws.prototype, 'init').returns(); - it('should mark the subsegment as throttled and error if code service.throttledError returns true, regardless of status code', async function() { - var throttleStub = sandbox.stub(sub, 'addThrottleFlag').returns(); + awsRequest.response = { + error: { message: 'throttling', code: 'ProvisionedThroughputExceededException' }, + $metadata: { httpStatusCode: 400 }, + }; - sandbox.stub(contextUtils, 'isAutomaticMode').returns(true); - sandbox.stub(sub, 'addAttribute').returns(); - sandbox.stub(Aws.prototype, 'init').returns(); + await awsClient.send(awsRequest).catch(() => null); - awsRequest.response = { - error: { message: 'throttling', code: 'ProvisionedThroughputExceededException' }, - $metadata: { httpStatusCode: 400 }, - }; + throttleStub.should.have.been.calledOnce; + assert.isTrue(sub.error); + }); - await awsClient.send(awsRequest).catch(() => null); + it('should capture an error on the response and mark exception as remote', async function() { + const closeStub = sandbox.stub(sub, 'close').returns(); + const getCauseStub = sandbox.stub(Utils, 'getCauseTypeFromHttpStatus').returns(); - throttleStub.should.have.been.calledOnce; - assert.isTrue(sub.error); + sandbox.stub(sub, 'addAttribute').returns(); + sandbox.stub(Aws.prototype, 'init').returns(); + + const error = { message: 'big error', code: 'Error' }; + + awsRequest.response = { + error, + $metadata: { httpStatusCode: 500 }, + }; + + await awsClient.send(awsRequest).catch(() => null); + + getCauseStub.should.have.been.calledWithExactly(500); + closeStub.should.have.been.calledWithExactly(sinon.match({ message: error.message, name: error.code}), true); + }); }); - it('should capture an error on the response and mark exception as remote', async function() { - var closeStub = sandbox.stub(sub, 'close').returns(); - var getCauseStub = sandbox.stub(Utils, 'getCauseTypeFromHttpStatus').returns(); + describe('#manualMode', () => { + beforeEach(() => { + sandbox.stub(contextUtils, 'isAutomaticMode').returns(false); + }); - sandbox.stub(contextUtils, 'isAutomaticMode').returns(true); - sandbox.stub(sub, 'addAttribute').returns(); - sandbox.stub(Aws.prototype, 'init').returns(); + it('should log an info statement and exit if parent is not found in the context for manual mode', (done) => { + awsClient = awsPatcher.captureAWSClient(awsClient); + var logStub = sandbox.stub(logger, 'info'); - var error = { message: 'big error', code: 'Error' }; + awsClient.send(awsRequest); - awsRequest.response = { - error, - $metadata: { httpStatusCode: 500 }, - }; + setTimeout(function() { + logStub.should.have.been.calledOnce; + done(); + }, 50); + }); + + it('should use the provided parent segment', () => { + awsClient = awsPatcher.captureAWSClient(awsClient, segment); + + awsClient.send(awsRequest); + + assert.isTrue(addNewSubsegmentStub.calledWith('S3')); + }); + + it('should handle several calls to capture', () => { + const otherSeg = new Segment('otherTest'); + const otherAddNewStub = sandbox.stub(otherSeg, 'addNewSubsegment'); - await awsClient.send(awsRequest).catch(() => null); + awsClient = awsPatcher.captureAWSClient(awsClient, segment); + awsClient.send(awsRequest); + assert.isTrue(addNewSubsegmentStub.calledWith('S3')); - getCauseStub.should.have.been.calledWithExactly(500); - closeStub.should.have.been.calledWithExactly(sinon.match({ message: error.message, name: error.code}), true); + awsClient = awsPatcher.captureAWSClient(awsClient, otherSeg); + awsClient.send(awsRequest); + assert.isTrue(otherAddNewStub.calledWith('S3')); + }); }); }); });