diff --git a/.eslintrc b/.eslintrc index 844b2c40..4b88f764 100644 --- a/.eslintrc +++ b/.eslintrc @@ -17,6 +17,7 @@ "jest": true }, "rules": { + "arrow-parens": ["error", "as-needed"], "@typescript-eslint/lines-between-class-members": "off", "max-len": "off", "class-methods-use-this": "off", diff --git a/CHANGELOG.md b/CHANGELOG.md index a87a80d5..9e407047 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +### 1.5.0 + +`ContentAttachments` fixes for all attachments. ([#23](https://github.com/MrRefactoring/confluence.js/issues/23) Thanks [Anton](https://github.com/tester22) for catching) + ### 1.4.1 - Dependencies updated. diff --git a/package-lock.json b/package-lock.json index 602ffd3a..15dd4ec5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,23 +1,23 @@ { "name": "confluence.js", - "version": "1.4.1", + "version": "1.5.0", "lockfileVersion": 1, "requires": true, "dependencies": { "@eslint/eslintrc": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.2.tgz", - "integrity": "sha512-lTVWHs7O2hjBFZunXTZYnYqtB9GakA1lnxIf+gKq2nY5gxkkNi/lQvveW6t8gFdOHTg6nG50Xs95PrLqVpcaLg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", + "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.3.1", - "globals": "^13.9.0", + "espree": "^9.3.2", + "globals": "^13.15.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, "dependencies": { @@ -117,147 +117,146 @@ "dev": true }, "@swc-node/core": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/@swc-node/core/-/core-1.8.2.tgz", - "integrity": "sha512-IoJ7tGHQ6JOMSmFe4VhP64uLmFKMNasS0QEgUrLFQ0h/dTvpQMynnoGBEJoPL6LfsebZ/q4uKqbpWrth6/yrAA==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@swc-node/core/-/core-1.9.0.tgz", + "integrity": "sha512-vRnvsMtL9OxybA/Wun1ZhlDvB6MNs4Zujnina0VKdGk+yI6s87KUhdTcbAY6dQMZhQTLFiC1Lnv/BuwCKcCEug==", "dev": true, "requires": { - "@swc/core": "^1.2.119" + "@swc/core": "^1.2.172" } }, "@swc-node/register": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@swc-node/register/-/register-1.4.2.tgz", - "integrity": "sha512-wLZz0J7BTO//1Eq7e4eBQjKF380Hr2eVemz849msQSKcVM1D7UJUt/dP2TinEVGx++/BXJ/0q37i6n9Iw0EM0w==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@swc-node/register/-/register-1.5.1.tgz", + "integrity": "sha512-6IL5s4QShKGs08qAeNou3rDA3gbp2WHk6fo0XnJXQn/aC9k6FnVBbj/thGOIEDtgNhC/DKpZT8tCY1LpQnOZFg==", "dev": true, "requires": { - "@swc-node/core": "^1.8.2", - "@swc-node/sourcemap-support": "^0.1.11", - "chalk": "4", - "debug": "^4.3.3", - "pirates": "^4.0.4", - "tslib": "^2.3.1", - "typescript": "^4.5.3" + "@swc-node/core": "^1.9.0", + "@swc-node/sourcemap-support": "^0.2.0", + "colorette": "^2.0.16", + "debug": "^4.3.4", + "pirates": "^4.0.5", + "tslib": "^2.4.0" } }, "@swc-node/sourcemap-support": { - "version": "0.1.11", - "resolved": "https://registry.npmjs.org/@swc-node/sourcemap-support/-/sourcemap-support-0.1.11.tgz", - "integrity": "sha512-b+Mn3oQl+7nUSt7hPzIbY9B30YhcFo1PT4kd9P4QmD6raycmIealOAhAdZID/JevphzsOXHQB4OqJm7Yi5tMcA==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@swc-node/sourcemap-support/-/sourcemap-support-0.2.0.tgz", + "integrity": "sha512-FNrxdI6XMYfoNt81L8eFKEm1d8P82I1nPwS3MrnBGzZoMWB+seQhQK+iN6M5RreJxXbfZw5lF86LRjHEQeGMqg==", "dev": true, "requires": { "source-map-support": "^0.5.21" } }, "@swc/core": { - "version": "1.2.171", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.2.171.tgz", - "integrity": "sha512-WE1Nn+LQOqMb41jDTt78REE29elW4QvbAIECpAI9wUP4SJpt9uo9ItJQ3UbXE4BECQ0JgkLz5x7l9uWUAt4YUw==", - "dev": true, - "requires": { - "@swc/core-android-arm-eabi": "1.2.171", - "@swc/core-android-arm64": "1.2.171", - "@swc/core-darwin-arm64": "1.2.171", - "@swc/core-darwin-x64": "1.2.171", - "@swc/core-freebsd-x64": "1.2.171", - "@swc/core-linux-arm-gnueabihf": "1.2.171", - "@swc/core-linux-arm64-gnu": "1.2.171", - "@swc/core-linux-arm64-musl": "1.2.171", - "@swc/core-linux-x64-gnu": "1.2.171", - "@swc/core-linux-x64-musl": "1.2.171", - "@swc/core-win32-arm64-msvc": "1.2.171", - "@swc/core-win32-ia32-msvc": "1.2.171", - "@swc/core-win32-x64-msvc": "1.2.171" + "version": "1.2.186", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.2.186.tgz", + "integrity": "sha512-n+I0z+gIsk+rkO2/UYGLcnyI2bq0YcHFtnMynRtZ8v541luGszFLBrayd3ljnmt4mFzSPY+2gTSQgK5HNuYk5g==", + "dev": true, + "requires": { + "@swc/core-android-arm-eabi": "1.2.186", + "@swc/core-android-arm64": "1.2.186", + "@swc/core-darwin-arm64": "1.2.186", + "@swc/core-darwin-x64": "1.2.186", + "@swc/core-freebsd-x64": "1.2.186", + "@swc/core-linux-arm-gnueabihf": "1.2.186", + "@swc/core-linux-arm64-gnu": "1.2.186", + "@swc/core-linux-arm64-musl": "1.2.186", + "@swc/core-linux-x64-gnu": "1.2.186", + "@swc/core-linux-x64-musl": "1.2.186", + "@swc/core-win32-arm64-msvc": "1.2.186", + "@swc/core-win32-ia32-msvc": "1.2.186", + "@swc/core-win32-x64-msvc": "1.2.186" } }, "@swc/core-android-arm-eabi": { - "version": "1.2.171", - "resolved": "https://registry.npmjs.org/@swc/core-android-arm-eabi/-/core-android-arm-eabi-1.2.171.tgz", - "integrity": "sha512-0DZBYN8PX9GPWw2fJqKfVsctAFRVgQBM2Rin5ZRyJQehzTsI0HnandvFOZAS/I3T3YsiH4b5vH/S8KwRx+eCVg==", + "version": "1.2.186", + "resolved": "https://registry.npmjs.org/@swc/core-android-arm-eabi/-/core-android-arm-eabi-1.2.186.tgz", + "integrity": "sha512-y+xiLOlkksP69mCQTbSJi/TvELJ+VAVCS/A8xBynnbZXyst4byaEDz0b6PpSTeFU0QufyygzlIARBBxi48RAQg==", "dev": true, "optional": true }, "@swc/core-android-arm64": { - "version": "1.2.171", - "resolved": "https://registry.npmjs.org/@swc/core-android-arm64/-/core-android-arm64-1.2.171.tgz", - "integrity": "sha512-9ul8XoIeXf0iHt+S2R2GedWmv/iZPrmlAj81esf/mg541kajt3kfdHD+YMKFn753iOmgTfCM+TlU82XT4nEe3w==", + "version": "1.2.186", + "resolved": "https://registry.npmjs.org/@swc/core-android-arm64/-/core-android-arm64-1.2.186.tgz", + "integrity": "sha512-W7FZDXfs2b8UIsdBlyRbG8Me2L5k77nitd38LmPFzj9G67DQWhVyoCoHMx38kbsRE82GVO2LmZ28Ehrl7TQw5w==", "dev": true, "optional": true }, "@swc/core-darwin-arm64": { - "version": "1.2.171", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.2.171.tgz", - "integrity": "sha512-bZQLVbCRVU577LGXfhrDMqD0/cVvAFKRob3w2t/aZGY72rp9Mt56IPJcTIgah+5IeCapa4qwWwVQQVOP2DCcRA==", + "version": "1.2.186", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.2.186.tgz", + "integrity": "sha512-v0aKuzZEV8zqyxrFohVzKjbbOWllgUd0Mgs8Fbft/K7Brp4QzBXvSjhOwsnNE4AlwzRLdINQfQz/RO6Ygp9H4Q==", "dev": true, "optional": true }, "@swc/core-darwin-x64": { - "version": "1.2.171", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.2.171.tgz", - "integrity": "sha512-Geb3e9/o0h4VCky6dvQmHXwG+wpq0B4M0pkYySUMC3wVsqdun3rP2dF3i1FWG7F3t92sDOl3ba42JUweTtC2eA==", + "version": "1.2.186", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.2.186.tgz", + "integrity": "sha512-qhwFRvjFxkgiPqpg8ifo9bN6ONlPdn0xWPnkph2rpJhByMkNW2LEIApEPgS0ePhI9gq4Wksp5oxCviH1v36gQA==", "dev": true, "optional": true }, "@swc/core-freebsd-x64": { - "version": "1.2.171", - "resolved": "https://registry.npmjs.org/@swc/core-freebsd-x64/-/core-freebsd-x64-1.2.171.tgz", - "integrity": "sha512-JSsetNvKghKTXFyAu4+vW0pVY8sDGwZSBd3foyqyx5XXEQMDVlhQEs3AVtojp7+DQrh+PmUdyCB+zS74p70nzg==", + "version": "1.2.186", + "resolved": "https://registry.npmjs.org/@swc/core-freebsd-x64/-/core-freebsd-x64-1.2.186.tgz", + "integrity": "sha512-HhL4HqqShE3lCB7NWXRVjjiEN4t05usHrCBtHEADsZDAGglJRMjT9ZLGLVxGOxEziWCIR+kOV2jcMv0Bf4Bbaw==", "dev": true, "optional": true }, "@swc/core-linux-arm-gnueabihf": { - "version": "1.2.171", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.2.171.tgz", - "integrity": "sha512-ZYf5rED8Dw1dbYXolVEnexT7SYVpPJhsuKa4162Onsm/3S3xw1e+qmxJfTVdZG7jI8F2RDoZTHMLH+0y3iH98Q==", + "version": "1.2.186", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.2.186.tgz", + "integrity": "sha512-ouAREnVdbUnZA0y4wYdAZZKIvqJ1uer9hOCbafgGyrmR9i8Lhswz2fPUGOUc+rxjqsP1z7uN5CpMcAH4KvyNUQ==", "dev": true, "optional": true }, "@swc/core-linux-arm64-gnu": { - "version": "1.2.171", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.2.171.tgz", - "integrity": "sha512-uteuIg77MoEwdQ0BZPGFKmbDr+V2OP1rp/Dx9sU5/O9nd1Vju/tuCycMEv8X/k0Riza6sbK6xIFVAQlrPUTZ7g==", + "version": "1.2.186", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.2.186.tgz", + "integrity": "sha512-b8GbZ2FVlQrDWyqC/KW9zScAvvUx6StLDvGAPWxD2GvFHjE0iPnvLHGvuVuhje0pFFqSwZnQ5/KZ6VyrKowPJw==", "dev": true, "optional": true }, "@swc/core-linux-arm64-musl": { - "version": "1.2.171", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.2.171.tgz", - "integrity": "sha512-d1mKKb9QaIOp3KQKvPT8pFgPvZXpYc/YHnyyI667BUboKuznB9VDpHeXk6+C/SWUIT9QdStc0fcf/Tnwni+ivA==", + "version": "1.2.186", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.2.186.tgz", + "integrity": "sha512-vWvfQiC7K2oMxuKbAWTgVVoTs7SpHb8GyecAzQbQWNIyOycLMihCXhgj99cz0GaSeEs/0SEd+FSoU+uldUysjA==", "dev": true, "optional": true }, "@swc/core-linux-x64-gnu": { - "version": "1.2.171", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.2.171.tgz", - "integrity": "sha512-CUNv0yNFuO4y0AnOq9Zbs44nBEuS+eLqC3gv2nEFovdUeVy71rRVelMjvdF5ZWXitHk+WjhfBznF+vP9pye3HA==", + "version": "1.2.186", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.2.186.tgz", + "integrity": "sha512-lGBOQd9GZsk6JQd1teZPIirir4vpcGPFlEKaoWMHTVgb4wyU0I6sW2edoHMWu+mUugs12/JpHWh7sw+ubgZzHA==", "dev": true, "optional": true }, "@swc/core-linux-x64-musl": { - "version": "1.2.171", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.2.171.tgz", - "integrity": "sha512-orHpb/THPJOaDJkJvzGRppwOd0tmpk3ZUGTgRD6FhzYrGzESxEhXuPYNE2jlaXx9hBxu9YDRMUvJWsmLDZW3GQ==", + "version": "1.2.186", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.2.186.tgz", + "integrity": "sha512-H6pFxBpg3R+g0DDXzs39c9A7+O/ai1Zwliwo7jwOfLu4ef/cq2xrKa0AJ22lawtU9A+4gwRCX78phf2ezjC2jw==", "dev": true, "optional": true }, "@swc/core-win32-arm64-msvc": { - "version": "1.2.171", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.2.171.tgz", - "integrity": "sha512-zdoPPnTC5li+4ijatjZA+qyrPTQzpmOqjtQ6HAx1yLoJriGLteLfYmjplx5sFI3JrcDXzITVjaGmu3Ep4Jmhtw==", + "version": "1.2.186", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.2.186.tgz", + "integrity": "sha512-B178S3J5L9Z21IBVMNCarvM6kQrxHQVtT8V7vhUgldPJ5Nc2ty7ELYvrSdtiARqKP5PacKMur+nb8XIyhoJfIw==", "dev": true, "optional": true }, "@swc/core-win32-ia32-msvc": { - "version": "1.2.171", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.2.171.tgz", - "integrity": "sha512-AmaOwrjnIQffwqrCL1MfSpG//ZbtdcCVqhY3+UtVmfKoSsSSkgWXSV++PQlJApAgRn/iwjZiR816B7zLg6535g==", + "version": "1.2.186", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.2.186.tgz", + "integrity": "sha512-0VqhXRn+MVth9hdwRR/X0unT9hdUOa5Y8FRUgMm3ft/72bFSAz3E8UNYMWMtVbjuViNYJgAOPML+VE9UqN80JQ==", "dev": true, "optional": true }, "@swc/core-win32-x64-msvc": { - "version": "1.2.171", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.2.171.tgz", - "integrity": "sha512-DrOqi27Lagn/wy2QYDOiNr0KAJX4yR0areDcli2NQ875tva5uVFgvZo5sJFsHiLU/x6yBcxVpVAbzg8a1jRUAA==", + "version": "1.2.186", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.2.186.tgz", + "integrity": "sha512-T+sNpLbtg5Q1zrDIOwzRDVCKQHb4eQx8MlIk9tF74amlBLt1GKBdgRn17YAA6GrNHRw7QHaDIeCEdc5OuUztvg==", "dev": true, "optional": true }, @@ -404,98 +403,98 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "5.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.21.0.tgz", - "integrity": "sha512-fTU85q8v5ZLpoZEyn/u1S2qrFOhi33Edo2CZ0+q1gDaWWm0JuPh3bgOyU8lM0edIEYgKLDkPFiZX2MOupgjlyg==", + "version": "5.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.25.0.tgz", + "integrity": "sha512-icYrFnUzvm+LhW0QeJNKkezBu6tJs9p/53dpPLFH8zoM9w1tfaKzVurkPotEpAqQ8Vf8uaFyL5jHd0Vs6Z0ZQg==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.21.0", - "@typescript-eslint/type-utils": "5.21.0", - "@typescript-eslint/utils": "5.21.0", - "debug": "^4.3.2", + "@typescript-eslint/scope-manager": "5.25.0", + "@typescript-eslint/type-utils": "5.25.0", + "@typescript-eslint/utils": "5.25.0", + "debug": "^4.3.4", "functional-red-black-tree": "^1.0.1", - "ignore": "^5.1.8", + "ignore": "^5.2.0", "regexpp": "^3.2.0", - "semver": "^7.3.5", + "semver": "^7.3.7", "tsutils": "^3.21.0" } }, "@typescript-eslint/parser": { - "version": "5.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.21.0.tgz", - "integrity": "sha512-8RUwTO77hstXUr3pZoWZbRQUxXcSXafZ8/5gpnQCfXvgmP9gpNlRGlWzvfbEQ14TLjmtU8eGnONkff8U2ui2Eg==", + "version": "5.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.25.0.tgz", + "integrity": "sha512-r3hwrOWYbNKP1nTcIw/aZoH+8bBnh/Lh1iDHoFpyG4DnCpvEdctrSl6LOo19fZbzypjQMHdajolxs6VpYoChgA==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.21.0", - "@typescript-eslint/types": "5.21.0", - "@typescript-eslint/typescript-estree": "5.21.0", - "debug": "^4.3.2" + "@typescript-eslint/scope-manager": "5.25.0", + "@typescript-eslint/types": "5.25.0", + "@typescript-eslint/typescript-estree": "5.25.0", + "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "5.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.21.0.tgz", - "integrity": "sha512-XTX0g0IhvzcH/e3393SvjRCfYQxgxtYzL3UREteUneo72EFlt7UNoiYnikUtmGVobTbhUDByhJ4xRBNe+34kOQ==", + "version": "5.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.25.0.tgz", + "integrity": "sha512-p4SKTFWj+2VpreUZ5xMQsBMDdQ9XdRvODKXN4EksyBjFp2YvQdLkyHqOffakYZPuWJUDNu3jVXtHALDyTv3cww==", "dev": true, "requires": { - "@typescript-eslint/types": "5.21.0", - "@typescript-eslint/visitor-keys": "5.21.0" + "@typescript-eslint/types": "5.25.0", + "@typescript-eslint/visitor-keys": "5.25.0" } }, "@typescript-eslint/type-utils": { - "version": "5.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.21.0.tgz", - "integrity": "sha512-MxmLZj0tkGlkcZCSE17ORaHl8Th3JQwBzyXL/uvC6sNmu128LsgjTX0NIzy+wdH2J7Pd02GN8FaoudJntFvSOw==", + "version": "5.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.25.0.tgz", + "integrity": "sha512-B6nb3GK3Gv1Rsb2pqalebe/RyQoyG/WDy9yhj8EE0Ikds4Xa8RR28nHz+wlt4tMZk5bnAr0f3oC8TuDAd5CPrw==", "dev": true, "requires": { - "@typescript-eslint/utils": "5.21.0", - "debug": "^4.3.2", + "@typescript-eslint/utils": "5.25.0", + "debug": "^4.3.4", "tsutils": "^3.21.0" } }, "@typescript-eslint/types": { - "version": "5.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.21.0.tgz", - "integrity": "sha512-XnOOo5Wc2cBlq8Lh5WNvAgHzpjnEzxn4CJBwGkcau7b/tZ556qrWXQz4DJyChYg8JZAD06kczrdgFPpEQZfDsA==", + "version": "5.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.25.0.tgz", + "integrity": "sha512-7fWqfxr0KNHj75PFqlGX24gWjdV/FDBABXL5dyvBOWHpACGyveok8Uj4ipPX/1fGU63fBkzSIycEje4XsOxUFA==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.21.0.tgz", - "integrity": "sha512-Y8Y2T2FNvm08qlcoSMoNchh9y2Uj3QmjtwNMdRQkcFG7Muz//wfJBGBxh8R7HAGQFpgYpdHqUpEoPQk+q9Kjfg==", + "version": "5.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.25.0.tgz", + "integrity": "sha512-MrPODKDych/oWs/71LCnuO7NyR681HuBly2uLnX3r5i4ME7q/yBqC4hW33kmxtuauLTM0OuBOhhkFaxCCOjEEw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.21.0", - "@typescript-eslint/visitor-keys": "5.21.0", - "debug": "^4.3.2", - "globby": "^11.0.4", + "@typescript-eslint/types": "5.25.0", + "@typescript-eslint/visitor-keys": "5.25.0", + "debug": "^4.3.4", + "globby": "^11.1.0", "is-glob": "^4.0.3", - "semver": "^7.3.5", + "semver": "^7.3.7", "tsutils": "^3.21.0" } }, "@typescript-eslint/utils": { - "version": "5.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.21.0.tgz", - "integrity": "sha512-q/emogbND9wry7zxy7VYri+7ydawo2HDZhRZ5k6yggIvXa7PvBbAAZ4PFH/oZLem72ezC4Pr63rJvDK/sTlL8Q==", + "version": "5.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.25.0.tgz", + "integrity": "sha512-qNC9bhnz/n9Kba3yI6HQgQdBLuxDoMgdjzdhSInZh6NaDnFpTUlwNGxplUFWfY260Ya0TRPvkg9dd57qxrJI9g==", "dev": true, "requires": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.21.0", - "@typescript-eslint/types": "5.21.0", - "@typescript-eslint/typescript-estree": "5.21.0", + "@typescript-eslint/scope-manager": "5.25.0", + "@typescript-eslint/types": "5.25.0", + "@typescript-eslint/typescript-estree": "5.25.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0" } }, "@typescript-eslint/visitor-keys": { - "version": "5.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.21.0.tgz", - "integrity": "sha512-SX8jNN+iHqAF0riZQMkm7e8+POXa/fXw5cxL+gjpyP+FI+JVNhii53EmQgDAfDcBpFekYSlO0fGytMQwRiMQCA==", + "version": "5.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.25.0.tgz", + "integrity": "sha512-yd26vFgMsC4h2dgX4+LR+GeicSKIfUvZREFLf3DDjZPtqgLx5AJZr6TetMNwFP9hcKreTTeztQYBTNbNoOycwA==", "dev": true, "requires": { - "@typescript-eslint/types": "5.21.0", - "eslint-visitor-keys": "^3.0.0" + "@typescript-eslint/types": "5.25.0", + "eslint-visitor-keys": "^3.3.0" } }, "acorn": { @@ -632,7 +631,7 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "atlassian-jwt": { "version": "2.0.2", @@ -738,9 +737,9 @@ } }, "axios": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.0.tgz", - "integrity": "sha512-XV/WrPxXfzgZ8j4lcB5i6LyaXmi90yetmV/Fem0kmglGx+mpY06CiweL3YxU6wOTNLmqLUePW4G8h45nGZ/+pA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", "requires": { "follow-redirects": "^1.14.9", "form-data": "^4.0.0" @@ -967,6 +966,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "colorette": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", + "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", + "dev": true + }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -1147,9 +1152,9 @@ } }, "dotenv": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.0.tgz", - "integrity": "sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==", + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", + "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==", "dev": true }, "eastasianwidth": { @@ -1231,12 +1236,12 @@ "dev": true }, "eslint": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.14.0.tgz", - "integrity": "sha512-3/CE4aJX7LNEiE3i6FeodHmI/38GZtWCsAtsymScmzYapx8q1nVVb+eLcLSzATmCPXw5pT4TqVs1E0OmxAd9tw==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.16.0.tgz", + "integrity": "sha512-MBndsoXY/PeVTDJeWsYj7kLZ5hQpJOfMYLsF6LicLHQWbRDG19lK5jOix4DPl8yY4SUFcE3txy86OzFLWT+yoA==", "dev": true, "requires": { - "@eslint/eslintrc": "^1.2.2", + "@eslint/eslintrc": "^1.3.0", "@humanwhocodes/config-array": "^0.9.2", "ajv": "^6.10.0", "chalk": "^4.0.0", @@ -1247,14 +1252,14 @@ "eslint-scope": "^7.1.1", "eslint-utils": "^3.0.0", "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.1", + "espree": "^9.3.2", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", "glob-parent": "^6.0.1", - "globals": "^13.6.0", + "globals": "^13.15.0", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", @@ -1263,7 +1268,7 @@ "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.1", "regexpp": "^3.2.0", @@ -1555,14 +1560,22 @@ "dev": true }, "espree": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", - "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", + "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", "dev": true, "requires": { - "acorn": "^8.7.0", - "acorn-jsx": "^5.3.1", + "acorn": "^8.7.1", + "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.3.0" + }, + "dependencies": { + "acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true + } } }, "esprima": { @@ -1718,9 +1731,9 @@ "dev": true }, "follow-redirects": { - "version": "1.14.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", - "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==" + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.0.tgz", + "integrity": "sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ==" }, "form-data": { "version": "4.0.0", @@ -1808,9 +1821,9 @@ } }, "globals": { - "version": "13.13.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", - "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "version": "13.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", + "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -3092,9 +3105,9 @@ "dev": true }, "sinon": { - "version": "13.0.2", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-13.0.2.tgz", - "integrity": "sha512-KvOrztAVqzSJWMDoxM4vM+GPys1df2VBoXm+YciyB/OLMamfS3VXh3oGh5WtrAGSzrgczNWFFY22oKb7Fi5eeA==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-14.0.0.tgz", + "integrity": "sha512-ugA6BFmE+WrJdh0owRZHToLd32Uw3Lxq6E6LtNRU+xTVBefx632h03Q7apXWRsRdZAJ41LB8aUfn2+O4jsDNMw==", "dev": true, "requires": { "@sinonjs/commons": "^1.8.3", @@ -3369,9 +3382,9 @@ "dev": true }, "typescript": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz", - "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==", + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", "dev": true }, "unbox-primitive": { diff --git a/package.json b/package.json index 5e3272bf..ba773266 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "confluence.js", - "version": "1.4.1", + "version": "1.5.0", "description": "confluence.js is a powerful Node.JS/Browser module that allows you to interact with the Confluence API very easily", "author": "Vladislav Tupikin ", "license": "MIT", @@ -14,7 +14,7 @@ "test": "npm run test:unit && npm run test:e2e", "prettier": "prettier --write src/**/*.ts", "doc": "typedoc --name \"Confluence.js - Cloud and Server API library\" --out docs ./src/index.ts --plugin typedoc-plugin-extras --footerDate --footerTime --footerTypedocVersion --favicon https://svgshare.com/i/bVi.svg", - "lint": "eslint src --ext .ts", + "lint": "eslint src tests --ext .ts", "lint:fix": "npm run lint -- --fix", "test:unit": "ava tests/unit", "test:e2e": "ava --timeout=2m --fail-fast --no-worker-threads -c 1 -s tests/e2e/**/*.test.ts" @@ -36,34 +36,36 @@ "api", "wrapper", "client", + "cloud", "rest", "wiki", "atlassian" ], "devDependencies": { - "@swc-node/register": "^1.4.2", + "@swc-node/register": "^1.5.1", "@types/express": "^4.17.13", "@types/oauth": "^0.9.1", "@types/sinon": "^10.0.11", - "@typescript-eslint/eslint-plugin": "^5.21.0", - "@typescript-eslint/parser": "^5.21.0", + "@typescript-eslint/eslint-plugin": "^5.25.0", + "@typescript-eslint/parser": "^5.25.0", "ava": "^4.2.0", - "dotenv": "^16.0.0", - "eslint": "^8.14.0", + "dotenv": "^16.0.1", + "eslint": "^8.16.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-airbnb-typescript": "^17.0.0", "eslint-import-resolver-typescript": "^2.7.1", "eslint-plugin-import": "^2.26.0", "prettier": "^2.6.2", "prettier-plugin-jsdoc": "^0.3.38", - "sinon": "^13.0.2", + "sinon": "^14.0.0", "typedoc": "^0.22.15", "typedoc-plugin-extras": "^2.2.3", - "typescript": "^4.6.3" + "typescript": "^4.6.4" }, "dependencies": { "atlassian-jwt": "^2.0.2", - "axios": "^0.27.0", + "axios": "^0.27.2", + "form-data": "^4.0.0", "oauth": "^0.9.15", "tslib": "^2.4.0" } diff --git a/src/api/contentAttachments.ts b/src/api/contentAttachments.ts index 333ec693..8fc7d58f 100644 --- a/src/api/contentAttachments.ts +++ b/src/api/contentAttachments.ts @@ -1,3 +1,4 @@ +import * as FormData from 'form-data'; import * as Models from './models'; import * as Parameters from './parameters'; import { Callback } from '../callback'; @@ -15,7 +16,7 @@ export class ContentAttachments { * **[Permissions](https://confluence.atlassian.com/x/_AozKw) required**: Permission to view the content. If the * content is a blog post, 'View' permission for the space is required. */ - async getAttachments( + async getAttachments>( parameters: Parameters.GetAttachments, callback: Callback ): Promise; @@ -27,8 +28,8 @@ export class ContentAttachments { * **[Permissions](https://confluence.atlassian.com/x/_AozKw) required**: Permission to view the content. If the * content is a blog post, 'View' permission for the space is required. */ - async getAttachments(parameters: Parameters.GetAttachments, callback?: never): Promise; - async getAttachments( + async getAttachments>(parameters: Parameters.GetAttachments, callback?: never): Promise; + async getAttachments>( parameters: Parameters.GetAttachments, callback?: Callback, ): Promise { @@ -49,91 +50,55 @@ export class ContentAttachments { /** * Adds an attachment to a piece of content. This method only adds a new attachment. If you want to update an existing - * attachment, use [Create or update attachments](#api-content-id-child-attachment-put). - * - * Note, you must set a `X-Atlassian-Token: nocheck` header on the request for this method, otherwise it will be - * blocked. This protects against XSRF attacks, which is necessary as this method accepts multipart/form-data. - * - * The media type 'multipart/form-data' is defined in [RFC 7578](https://www.ietf.org/rfc/rfc7578.txt). Most client - * libraries have classes that make it easier to implement multipart posts, like the - * [MultipartEntityBuilder](https://hc.apache.org/httpcomponents-client-5.1.x/current/httpclient5/apidocs/) Java class - * provided by Apache HTTP Components. - * - * Note, according to [RFC 7578](https://tools.ietf.org/html/rfc7578#section-4.5), in the case where the form data is - * text, the charset parameter for the "text/plain" Content-Type may be used to indicate the character encoding used - * in that part. In the case of this API endpoint, the `comment` body parameter should be sent with `type=text/plain` - * and `charset=utf-8` values. This will force the charset to be UTF-8. - * - * Example: This curl command attaches a file ('example.txt') to a container (id='123') with a comment and `minorEdits`=true. - * - * ```bash - * curl -D- \ - * -u admin:admin \ - * -X POST \ - * -H 'X-Atlassian-Token: nocheck' \ - * -F 'file=@"example.txt"' \ - * -F 'minorEdit="true"' \ - * -F 'comment="Example attachment comment"; type=text/plain; charset=utf-8' \ - * http://myhost/rest/api/content/123/child/attachment - * ``` + * attachment, use [Create or update attachments](https://developer.atlassian.com/cloud/confluence/rest/api-group-content---attachments/#api-wiki-rest-api-content-id-child-attachment-put). * * **[Permissions](https://confluence.atlassian.com/x/_AozKw) required**: Permission to update the content. */ - async createAttachments( + async createAttachments>( parameters: Parameters.CreateAttachments, callback: Callback ): Promise; /** * Adds an attachment to a piece of content. This method only adds a new attachment. If you want to update an existing - * attachment, use [Create or update attachments](#api-content-id-child-attachment-put). - * - * Note, you must set a `X-Atlassian-Token: nocheck` header on the request for this method, otherwise it will be - * blocked. This protects against XSRF attacks, which is necessary as this method accepts multipart/form-data. - * - * The media type 'multipart/form-data' is defined in [RFC 7578](https://www.ietf.org/rfc/rfc7578.txt). Most client - * libraries have classes that make it easier to implement multipart posts, like the - * [MultipartEntityBuilder](https://hc.apache.org/httpcomponents-client-5.1.x/current/httpclient5/apidocs/) Java class - * provided by Apache HTTP Components. - * - * Note, according to [RFC 7578](https://tools.ietf.org/html/rfc7578#section-4.5), in the case where the form data is - * text, the charset parameter for the "text/plain" Content-Type may be used to indicate the character encoding used - * in that part. In the case of this API endpoint, the `comment` body parameter should be sent with `type=text/plain` - * and `charset=utf-8` values. This will force the charset to be UTF-8. - * - * Example: This curl command attaches a file ('example.txt') to a container (id='123') with a comment and `minorEdits`=true. - * - * ```bash - * curl -D- \ - * -u admin:admin \ - * -X POST \ - * -H 'X-Atlassian-Token: nocheck' \ - * -F 'file=@"example.txt"' \ - * -F 'minorEdit="true"' \ - * -F 'comment="Example attachment comment"; type=text/plain; charset=utf-8' \ - * http://myhost/rest/api/content/123/child/attachment - * ``` + * attachment, use [Create or update attachments](https://developer.atlassian.com/cloud/confluence/rest/api-group-content---attachments/#api-wiki-rest-api-content-id-child-attachment-put). * * **[Permissions](https://confluence.atlassian.com/x/_AozKw) required**: Permission to update the content. */ - async createAttachments( + async createAttachments>( parameters: Parameters.CreateAttachments, callback?: never ): Promise; - async createAttachments( + async createAttachments>( parameters: Parameters.CreateAttachments, callback?: Callback, ): Promise { + const formData = new FormData(); + const attachments = Array.isArray(parameters.attachments) ? parameters.attachments : [parameters.attachments]; + + attachments.forEach(attachment => { + formData.append('minorEdit', attachment.minorEdit.toString(), 'minorEdit'); + formData.append('file', attachment.file, { + filename: attachment.filename, + contentType: attachment.contentType, + }); + + if (attachment.comment) { + formData.append('comment', attachment.comment, 'comment'); + } + }); + const config: RequestConfig = { url: `/api/content/${parameters.id}/child/attachment`, method: 'POST', + headers: { + 'X-Atlassian-Token': 'no-check', + 'Content-Type': 'multipart/form-data', + ...formData.getHeaders?.(), + }, params: { status: parameters.status, }, - data: { - ...parameters, - id: undefined, - status: undefined, - }, + data: formData, }; return this.client.sendRequest(config, callback); @@ -143,36 +108,9 @@ export class ContentAttachments { * Adds an attachment to a piece of content. If the attachment already exists for the content, then the attachment is * updated (i.e. a new version of the attachment is created). * - * Note, you must set a `X-Atlassian-Token: nocheck` header on the request for this method, otherwise it will be - * blocked. This protects against XSRF attacks, which is necessary as this method accepts multipart/form-data. - * - * The media type 'multipart/form-data' is defined in [RFC 7578](https://www.ietf.org/rfc/rfc7578.txt). Most client - * libraries have classes that make it easier to implement multipart posts, like the - * [MultipartEntityBuilder](https://hc.apache.org/httpcomponents-client-5.1.x/current/httpclient5/apidocs/) Java class - * provided by Apache HTTP Components. - * - * Note, according to [RFC 7578](https://tools.ietf.org/html/rfc7578#section-4.5), in the case where the form data is - * text, the charset parameter for the "text/plain" Content-Type may be used to indicate the character encoding used - * in that part. In the case of this API endpoint, the `comment` body parameter should be sent with `type=text/plain` - * and `charset=utf-8` values. This will force the charset to be UTF-8. - * - * Example: This curl command attaches a file ('example.txt') to a piece of content (id='123') with a comment and - * `minorEdits`=true. If the 'example.txt' file already exists, it will update it with a new version of the attachment. - * - * ```bash - * curl -D- \ - * -u admin:admin \ - * -X PUT \ - * -H 'X-Atlassian-Token: nocheck' \ - * -F 'file=@"example.txt"' \ - * -F 'minorEdit="true"' \ - * -F 'comment="Example attachment comment"; type=text/plain; charset=utf-8' \ - * http://myhost/rest/api/content/123/child/attachment - * ``` - * * **[Permissions](https://confluence.atlassian.com/x/_AozKw) required**: Permission to update the content. */ - async createOrUpdateAttachments( + async createOrUpdateAttachments>( parameters: Parameters.CreateOrUpdateAttachments, callback: Callback ): Promise; @@ -180,54 +118,43 @@ export class ContentAttachments { * Adds an attachment to a piece of content. If the attachment already exists for the content, then the attachment is * updated (i.e. a new version of the attachment is created). * - * Note, you must set a `X-Atlassian-Token: nocheck` header on the request for this method, otherwise it will be - * blocked. This protects against XSRF attacks, which is necessary as this method accepts multipart/form-data. - * - * The media type 'multipart/form-data' is defined in [RFC 7578](https://www.ietf.org/rfc/rfc7578.txt). Most client - * libraries have classes that make it easier to implement multipart posts, like the - * [MultipartEntityBuilder](https://hc.apache.org/httpcomponents-client-5.1.x/current/httpclient5/apidocs/) Java class - * provided by Apache HTTP Components. - * - * Note, according to [RFC 7578](https://tools.ietf.org/html/rfc7578#section-4.5), in the case where the form data is - * text, the charset parameter for the "text/plain" Content-Type may be used to indicate the character encoding used - * in that part. In the case of this API endpoint, the `comment` body parameter should be sent with `type=text/plain` - * and `charset=utf-8` values. This will force the charset to be UTF-8. - * - * Example: This curl command attaches a file ('example.txt') to a piece of content (id='123') with a comment and - * `minorEdits`=true. If the 'example.txt' file already exists, it will update it with a new version of the attachment. - * - * ```bash - * curl -D- \ - * -u admin:admin \ - * -X PUT \ - * -H 'X-Atlassian-Token: nocheck' \ - * -F 'file=@"example.txt"' \ - * -F 'minorEdit="true"' \ - * -F 'comment="Example attachment comment"; type=text/plain; charset=utf-8' \ - * http://myhost/rest/api/content/123/child/attachment - * ``` - * * **[Permissions](https://confluence.atlassian.com/x/_AozKw) required**: Permission to update the content. */ - async createOrUpdateAttachments( + async createOrUpdateAttachments>( parameters: Parameters.CreateOrUpdateAttachments, callback?: never ): Promise; - async createOrUpdateAttachments( + async createOrUpdateAttachments>( parameters: Parameters.CreateOrUpdateAttachments, callback?: Callback, ): Promise { + const formData = new FormData(); + const attachments = Array.isArray(parameters.attachments) ? parameters.attachments : [parameters.attachments]; + + attachments.forEach(attachment => { + formData.append('minorEdit', attachment.minorEdit.toString(), 'minorEdit'); + formData.append('file', attachment.file, { + filename: attachment.filename, + contentType: attachment.contentType, + }); + + if (attachment.comment) { + formData.append('comment', attachment.comment, 'comment'); + } + }); + const config: RequestConfig = { url: `/api/content/${parameters.id}/child/attachment`, method: 'PUT', + headers: { + 'X-Atlassian-Token': 'no-check', + 'Content-Type': 'multipart/form-data', + ...formData.getHeaders?.(), + }, params: { status: parameters.status, }, - data: { - ...parameters, - id: undefined, - status: undefined, - }, + data: formData, }; return this.client.sendRequest(config, callback); @@ -239,7 +166,7 @@ export class ContentAttachments { * * **[Permissions](https://confluence.atlassian.com/x/_AozKw) required**: Permission to update the content. */ - async updateAttachmentProperties( + async updateAttachmentProperties( parameters: Parameters.UpdateAttachmentProperties, callback: Callback ): Promise; @@ -249,18 +176,18 @@ export class ContentAttachments { * * **[Permissions](https://confluence.atlassian.com/x/_AozKw) required**: Permission to update the content. */ - async updateAttachmentProperties( + async updateAttachmentProperties( parameters: Parameters.UpdateAttachmentProperties, callback?: never ): Promise; - async updateAttachmentProperties( + async updateAttachmentProperties( parameters: Parameters.UpdateAttachmentProperties, callback?: Callback, ): Promise { const config: RequestConfig = { url: `/api/content/${parameters.id}/child/attachment/${parameters.attachmentId}`, method: 'PUT', - data: parameters.body, + data: parameters.update ?? parameters.body, }; return this.client.sendRequest(config, callback); @@ -269,106 +196,67 @@ export class ContentAttachments { /** * Updates the binary data of an attachment, given the attachment ID, and optionally the comment and the minor edit field. * - * This method is essentially the same as [Create or update attachments](#api-content-id-child-attachment-put), except + * This method is essentially the same as [Create or update attachments](https://developer.atlassian.com/cloud/confluence/rest/api-group-content---attachments/#api-wiki-rest-api-content-id-child-attachment-put), except * that it matches the attachment ID rather than the name. * - * Note, you must set a `X-Atlassian-Token: nocheck` header on the request for this method, otherwise it will be - * blocked. This protects against XSRF attacks, which is necessary as this method accepts multipart/form-data. - * - * The media type 'multipart/form-data' is defined in [RFC 7578](https://www.ietf.org/rfc/rfc7578.txt). Most client - * libraries have classes that make it easier to implement multipart posts, like the - * [MultipartEntityBuilder](https://hc.apache.org/httpcomponents-client-5.1.x/current/httpclient5/apidocs/) Java class - * provided by Apache HTTP Components. - * - * Note, according to [RFC 7578](https://tools.ietf.org/html/rfc7578#section-4.5), in the case where the form data is - * text, the charset parameter for the "text/plain" Content-Type may be used to indicate the character encoding used - * in that part. In the case of this API endpoint, the `comment` body parameter should be sent with `type=text/plain` - * and `charset=utf-8` values. This will force the charset to be UTF-8. - * - * Example: This curl command updates an attachment (id='att456') that is attached to a piece of content (id='123') - * with a comment and `minorEdits`=true. - * - * ```bash - * curl -D- \ - * -u admin:admin \ - * -X POST \ - * -H 'X-Atlassian-Token: nocheck' \ - * -F 'file=@"example.txt"' \ - * -F 'minorEdit="true"' \ - * -F 'comment="Example attachment comment"; type=text/plain; charset=utf-8' \ - * http://myhost/rest/api/content/123/child/attachment/att456/data - * ``` - * * **[Permissions](https://confluence.atlassian.com/x/_AozKw) required**: Permission to update the content. */ - async updateAttachmentData( + async updateAttachmentData( parameters: Parameters.UpdateAttachmentData, callback: Callback ): Promise; /** * Updates the binary data of an attachment, given the attachment ID, and optionally the comment and the minor edit field. * - * This method is essentially the same as [Create or update attachments](#api-content-id-child-attachment-put), except + * This method is essentially the same as [Create or update attachments](https://developer.atlassian.com/cloud/confluence/rest/api-group-content---attachments/#api-wiki-rest-api-content-id-child-attachment-put), except * that it matches the attachment ID rather than the name. * - * Note, you must set a `X-Atlassian-Token: nocheck` header on the request for this method, otherwise it will be - * blocked. This protects against XSRF attacks, which is necessary as this method accepts multipart/form-data. - * - * The media type 'multipart/form-data' is defined in [RFC 7578](https://www.ietf.org/rfc/rfc7578.txt). Most client - * libraries have classes that make it easier to implement multipart posts, like the - * [MultipartEntityBuilder](https://hc.apache.org/httpcomponents-client-5.1.x/current/httpclient5/apidocs/) Java class - * provided by Apache HTTP Components. - * - * Note, according to [RFC 7578](https://tools.ietf.org/html/rfc7578#section-4.5), in the case where the form data is - * text, the charset parameter for the "text/plain" Content-Type may be used to indicate the character encoding used - * in that part. In the case of this API endpoint, the `comment` body parameter should be sent with `type=text/plain` - * and `charset=utf-8` values. This will force the charset to be UTF-8. - * - * Example: This curl command updates an attachment (id='att456') that is attached to a piece of content (id='123') - * with a comment and `minorEdits`=true. - * - * ```bash - * curl -D- \ - * -u admin:admin \ - * -X POST \ - * -H 'X-Atlassian-Token: nocheck' \ - * -F 'file=@"example.txt"' \ - * -F 'minorEdit="true"' \ - * -F 'comment="Example attachment comment"; type=text/plain; charset=utf-8' \ - * http://myhost/rest/api/content/123/child/attachment/att456/data - * ``` - * * **[Permissions](https://confluence.atlassian.com/x/_AozKw) required**: Permission to update the content. */ - async updateAttachmentData( + async updateAttachmentData( parameters: Parameters.UpdateAttachmentData, callback?: never ): Promise; - async updateAttachmentData( + async updateAttachmentData( parameters: Parameters.UpdateAttachmentData, callback?: Callback, ): Promise { + const { attachment } = parameters; + + const formData = new FormData(); + + formData.append('minorEdit', attachment.minorEdit.toString(), 'minorEdit'); + formData.append('file', attachment.file, { + filename: attachment.filename, + contentType: attachment.contentType, + }); + + if (attachment.comment) { + formData.append('comment', attachment.comment, 'comment'); + } + const config: RequestConfig = { url: `/api/content/${parameters.id}/child/attachment/${parameters.attachmentId}/data`, method: 'POST', - data: { - ...parameters, - id: undefined, - attachmentId: undefined, + headers: { + 'X-Atlassian-Token': 'no-check', + 'Content-Type': 'multipart/form-data', + ...formData.getHeaders?.(), }, + data: formData, }; return this.client.sendRequest(config, callback); } /** Redirects the client to a URL that serves an attachment's binary data. */ - async downloadAttachment( + async downloadAttachment( parameters: Parameters.DownloadAttachment, callback: Callback ): Promise; /** Redirects the client to a URL that serves an attachment's binary data. */ - async downloadAttachment(parameters: Parameters.DownloadAttachment, callback?: never): Promise; - async downloadAttachment( + async downloadAttachment(parameters: Parameters.DownloadAttachment, callback?: never): Promise; + async downloadAttachment( parameters: Parameters.DownloadAttachment, callback?: Callback, ): Promise { diff --git a/src/api/models/attachment.ts b/src/api/models/attachment.ts new file mode 100644 index 00000000..f670bebe --- /dev/null +++ b/src/api/models/attachment.ts @@ -0,0 +1,31 @@ +import { AttachmentMetadata } from './attachmentMetadata'; +import { GenericLinks } from './genericLinks'; + +export interface Attachment { + id: string; + type: 'attachment' | string; + status: 'current' | string; + title: string; + macroRenderedOutput: any; + metadata: AttachmentMetadata; + extensions: { + mediaType: string; + fileSize: number; + comment: string; + mediaTypeDescription: string; + fileId: string; + }; + _expandable: { + childTypes: string; + operations: string; + schedulePublishDate: string; + children: string; + restrictions: string; + history: string; + ancestors: string; + body: string; + descendants: string; + space: string; + }; + _links: GenericLinks; +} diff --git a/src/api/models/attachmentContainer.ts b/src/api/models/attachmentContainer.ts new file mode 100644 index 00000000..da234ba9 --- /dev/null +++ b/src/api/models/attachmentContainer.ts @@ -0,0 +1,28 @@ +import { GenericLinks } from './genericLinks'; + +export interface AttachmentContainer { + id: string; + type: 'page' | 'string'; + status: 'current' | string; + title: string; + macroRenderedOutput: any; + extensions: { + position: number; + }; + _expandable: { + container: string; + metadata: string; + restrictions: string; + history:string; + body: string; + version: string; + descendants: string; + space: string; + childTypes: string; + operations: string; + schedulePublishDate: string; + children: string; + ancestors: string; + }; + _links: GenericLinks; +} diff --git a/src/api/models/attachmentMetadata.ts b/src/api/models/attachmentMetadata.ts new file mode 100644 index 00000000..3c76f309 --- /dev/null +++ b/src/api/models/attachmentMetadata.ts @@ -0,0 +1,21 @@ +import { GenericLinks } from './genericLinks'; + +export interface AttachmentMetadata { + comment: string; + mediaType: string; + labels: { + results: string[]; + start: number; + limit: number; + size: number; + _links: GenericLinks; + }; + _expandable: { + currentuser: string; + comments: string; + simple: string; + properties: string; + frontend: string; + likes: string; + }; +} diff --git a/src/api/models/attachmentUpdate.ts b/src/api/models/attachmentUpdate.ts index 574bcb3f..118ca19d 100644 --- a/src/api/models/attachmentUpdate.ts +++ b/src/api/models/attachmentUpdate.ts @@ -1,3 +1,4 @@ +/** @deprecated will be removed in second major version */ export interface AttachmentUpdate { /** * The attachment version. Set this to the current version number of the attachment. Note, the version number only diff --git a/src/api/models/contentArray.ts b/src/api/models/contentArray.ts index 3bb21b7b..79a36ad8 100644 --- a/src/api/models/contentArray.ts +++ b/src/api/models/contentArray.ts @@ -1,10 +1,10 @@ import { Content } from './content'; import { GenericLinks } from './genericLinks'; -export interface ContentArray { - results: Content[]; - start: number; - limit: number; +export interface ContentArray { + results: T[]; + start?: number; + limit?: number; size: number; _links: GenericLinks; } diff --git a/src/api/models/createdAttachment.ts b/src/api/models/createdAttachment.ts new file mode 100644 index 00000000..d4c29a8b --- /dev/null +++ b/src/api/models/createdAttachment.ts @@ -0,0 +1,8 @@ +import { Attachment } from './attachment'; +import { AttachmentContainer } from './attachmentContainer'; +import { Version } from './version'; + +export interface CreatedAttachment extends Attachment { + version: Version; + container: AttachmentContainer; +} diff --git a/src/api/models/genericLinks.ts b/src/api/models/genericLinks.ts index 1c7c206a..bddff584 100644 --- a/src/api/models/genericLinks.ts +++ b/src/api/models/genericLinks.ts @@ -1 +1,12 @@ -export type GenericLinks = Record; +export type GenericLinks = { + [key: string]: any; + + self: string; + next?: string; + tinyui?: string; + editui?: string; + webui?: string; + base?: string; + context?: string; + download?: string; +}; diff --git a/src/api/models/index.ts b/src/api/models/index.ts index a086ece6..87805bde 100644 --- a/src/api/models/index.ts +++ b/src/api/models/index.ts @@ -4,11 +4,14 @@ export * from './accountIdEmailRecordArray'; export * from './addContentRestriction'; export * from './addContentRestrictionUpdateArray'; export * from './affectedObject'; +export * from './attachmentContainer'; export * from './attachmentUpdate'; export * from './auditRecord'; export * from './auditRecordArray'; export * from './auditRecordCreate'; export * from './appDescriptor'; +export * from './attachment'; +export * from './attachmentMetadata'; export * from './blueprintTemplate'; export * from './blueprintTemplateArray'; export * from './breadcrumb'; @@ -60,6 +63,7 @@ export * from './copyPageRequest'; export * from './copyPageRequestDestination'; export * from './cQLPersonalDataConvertedQueries'; export * from './cQLPersonalDataMigrationRequest'; +export * from './createdAttachment'; export * from './deletedSpace'; export * from './dynamicModulesErrorMessage'; export * from './embeddable'; diff --git a/src/api/parameters/createAttachments.ts b/src/api/parameters/createAttachments.ts index 5a9d5001..b9135555 100644 --- a/src/api/parameters/createAttachments.ts +++ b/src/api/parameters/createAttachments.ts @@ -2,7 +2,17 @@ export interface CreateAttachments { /** The ID of the content to add the attachment to. */ id: string; /** The status of the content that the attachment is being added to. */ - status?: string; + status?: 'current' | 'draft' | string; + /** The attachments to be created. */ + attachments: CreateAttachments.Attachment | CreateAttachments.Attachment[]; +} - [key: string]: any; +export namespace CreateAttachments { + export interface Attachment { + file: Buffer | ReadableStream | string | Blob | File | any; + filename: string; + minorEdit: boolean; + contentType?: string; + comment?: string; + } } diff --git a/src/api/parameters/createOrUpdateAttachments.ts b/src/api/parameters/createOrUpdateAttachments.ts index 02f156bd..e975ca72 100644 --- a/src/api/parameters/createOrUpdateAttachments.ts +++ b/src/api/parameters/createOrUpdateAttachments.ts @@ -1,8 +1,11 @@ +import { CreateAttachments } from './createAttachments'; + export interface CreateOrUpdateAttachments { /** The ID of the content to add the attachment to. */ id: string; /** The status of the content that the attachment is being added to. This should always be set to 'current'. */ - status?: string; + status?: 'current' | 'draft' | string; - [key: string]: any; + /** The attachments to be created or updated. */ + attachments: CreateAttachments.Attachment | CreateAttachments.Attachment[]; } diff --git a/src/api/parameters/getAttachments.ts b/src/api/parameters/getAttachments.ts index d365bbd2..657279cf 100644 --- a/src/api/parameters/getAttachments.ts +++ b/src/api/parameters/getAttachments.ts @@ -2,7 +2,77 @@ export interface GetAttachments { /** The ID of the content to be queried for its attachments. */ id: string; /** A multi-value parameter indicating which properties of the content to expand. */ - expand?: string | string[] | GetAttachments.Expand | GetAttachments.Expand[]; + expand?: + | 'childTypes.all' + | 'childTypes.attachment' + | 'childTypes.comment' + | 'childTypes.page' + | 'container' + | 'metadata' + | 'metadata.currentuser' + | 'metadata.properties' + | 'metadata.labels' + | 'metadata.frontend' + | 'operations' + | 'children.page' + | 'children.attachment' + | 'children.comment' + | 'restrictions.read.restrictions.user' + | 'restrictions.read.restrictions.group' + | 'restrictions.update.restrictions.user' + | 'restrictions.update.restrictions.group' + | 'history' + | 'history.lastUpdated' + | 'history.previousVersion' + | 'history.contributors' + | 'history.nextVersion' + | 'ancestors' + | 'body' + | 'version' + | 'descendants.page' + | 'descendants.attachment' + | 'descendants.comment' + | 'space' + | 'extensions.inlineProperties' + | 'extensions.resolution' + | ( + | 'childTypes.all' + | 'childTypes.attachment' + | 'childTypes.comment' + | 'childTypes.page' + | 'container' + | 'metadata' + | 'metadata.currentuser' + | 'metadata.properties' + | 'metadata.labels' + | 'metadata.frontend' + | 'operations' + | 'children.page' + | 'children.attachment' + | 'children.comment' + | 'restrictions.read.restrictions.user' + | 'restrictions.read.restrictions.group' + | 'restrictions.update.restrictions.user' + | 'restrictions.update.restrictions.group' + | 'history' + | 'history.lastUpdated' + | 'history.previousVersion' + | 'history.contributors' + | 'history.nextVersion' + | 'ancestors' + | 'body' + | 'version' + | 'descendants.page' + | 'descendants.attachment' + | 'descendants.comment' + | 'space' + | 'extensions.inlineProperties' + | 'extensions.resolution' + )[] + | string + | string[] + | GetAttachments.Expand + | GetAttachments.Expand[]; /** The starting index of the returned attachments. */ start?: number; /** The maximum number of attachments to return per page. Note, this may be restricted by fixed system limits. */ diff --git a/src/api/parameters/updateAttachmentData.ts b/src/api/parameters/updateAttachmentData.ts index 26fad24d..207f1b84 100644 --- a/src/api/parameters/updateAttachmentData.ts +++ b/src/api/parameters/updateAttachmentData.ts @@ -1,8 +1,11 @@ -import { AttachmentUpdate } from '../models'; +import { CreateAttachments } from './createAttachments'; -export interface UpdateAttachmentData extends AttachmentUpdate { +export interface UpdateAttachmentData { /** The ID of the content that the attachment is attached to. */ id: string; /** The ID of the attachment to update. */ attachmentId: string; + + /** Attachment data to update. */ + attachment: CreateAttachments.Attachment; } diff --git a/src/api/parameters/updateAttachmentProperties.ts b/src/api/parameters/updateAttachmentProperties.ts index 6b22aea1..6db3dc30 100644 --- a/src/api/parameters/updateAttachmentProperties.ts +++ b/src/api/parameters/updateAttachmentProperties.ts @@ -1,4 +1,15 @@ -import { AttachmentUpdate } from '../models'; +import { + AttachmentMetadata, + Container, + Content, + ContentChildren, + ContentChildType, + ContentHistory, + GenericLinks, + OperationCheckResult, + Space, + Version, +} from '../models'; export interface UpdateAttachmentProperties { /** The ID of the content that the attachment is attached to. */ @@ -6,5 +17,51 @@ export interface UpdateAttachmentProperties { /** The ID of the attachment to update. */ attachmentId: string; - body: AttachmentUpdate; + /** @deprecated Use `update` property instead. */ + body?: UpdateAttachmentProperties.Properties; + + update?: UpdateAttachmentProperties.Properties; +} + +export namespace UpdateAttachmentProperties { + export interface Properties { + [key: string]: any; + + id: string; + type: 'page' | 'blogpost' | 'attachment' | 'content' | string; + status: 'current' | 'draft' | string; + title?: string; + space?: Space; + history?: ContentHistory; + version: Partial; + ancestors?: Content[]; + operations?: OperationCheckResult[]; + children?: ContentChildren; + childTypes?: ContentChildType; + descendants?: ContentChildren; + container?: Container; + body?: any; + restrictions?: any; + metadata?: Partial; + macroRenderedOutput?: any; + extensions?: any; + _expandable?: { + 'childTypes': string; + 'container': string; + 'metadata': string; + 'operations': string; + 'children': string; + 'restrictions': string; + 'history': string; + 'ancestors': string; + 'body': string; + 'version': string; + 'descendants': string; + 'space': string; + 'extensions': string; + 'schedulePublishDate': string; + 'macroRenderedOutput': string + }; + _links?: GenericLinks; + } } diff --git a/src/clients/baseClient.ts b/src/clients/baseClient.ts index 71edab2d..75a4a4ed 100644 --- a/src/clients/baseClient.ts +++ b/src/clients/baseClient.ts @@ -116,6 +116,8 @@ export class BaseClient implements Client { return responseHandler(response.data); } catch (e: any) { + const err = this.config.newErrorHandling && e.isAxiosError ? e.response.data : e; + const callbackErrorHandler = callback && ((error: Config.Error) => callback(error)); const defaultErrorHandler = (error: Error) => { throw error; @@ -123,9 +125,9 @@ export class BaseClient implements Client { const errorHandler = callbackErrorHandler ?? defaultErrorHandler; - this.config.middlewares?.onError?.(e); + this.config.middlewares?.onError?.(err); - return errorHandler(e); + return errorHandler(err); } } } diff --git a/src/config.ts b/src/config.ts index ef19e68c..8d7ce6a1 100644 --- a/src/config.ts +++ b/src/config.ts @@ -13,6 +13,8 @@ export interface Config { * Adds `'X-Atlassian-Token': 'no-check'` to each request header */ noCheckAtlassianToken?: boolean; + /** Enable new API error handling. `false` by default. */ + newErrorHandling?: boolean; } export namespace Config { diff --git a/src/paramSerializer.ts b/src/paramSerializer.ts index f29eb59a..f84a92ce 100644 --- a/src/paramSerializer.ts +++ b/src/paramSerializer.ts @@ -11,5 +11,5 @@ export function paramSerializer(key: string, values?: string | string[]) { return ''; } - return () => values.map((value) => `${key}=${value}`).join('&'); + return () => values.map(value => `${key}=${value}`).join('&'); } diff --git a/tests/e2e/e2e.test.ts b/tests/e2e/e2e.test.ts new file mode 100644 index 00000000..59a9eb90 --- /dev/null +++ b/tests/e2e/e2e.test.ts @@ -0,0 +1,181 @@ +import * as fs from 'fs'; +import { ConfluenceClient } from '../../src'; +import test from 'ava'; + +const HOST = process.env.HOST!; +const EMAIL = process.env.EMAIL!; +const API_TOKEN = process.env.API_TOKEN!; + +let createdContentId: string; +let createdAttachmentId: string; + +const client = new ConfluenceClient({ + host: HOST, + telemetry: false, + newErrorHandling: true, + authentication: { + basic: { + email: EMAIL, + apiToken: API_TOKEN, + }, + }, +}); + +test.serial('should create space', async t => { + const space = await client.space.createSpace({ + name: 'Auto testing software', + key: 'AUTOMATED', + }); + + t.truthy(!!space); + t.is(space.key, 'AUTOMATED'); + t.is(space.name, 'Auto testing software'); +}); + +test.serial('should create content', async t => { + const content = await client.content.createContent({ + title: 'Test page', + space: { + key: 'AUTOMATED', + }, + type: 'page', + body: { + view: { + value: '', + representation: 'view', + }, + }, + }); + + createdContentId = content.id; + + t.truthy(!!content); + t.is(content.type, 'page'); + t.is(content.space?.key, 'AUTOMATED'); +}); + +test.serial('should add attachment', async t => { + const file = await fs.readFileSync('./tests/unit/serverApiClient.test.ts'); + + const attachment = await client.contentAttachments.createAttachments({ + id: createdContentId, + attachments: { + file, + filename: 'serverApiClient.test.ts', + minorEdit: true, + comment: 'heh comment', + contentType: 'application/javascript', + }, + }); + + t.truthy(!!attachment); + t.truthy(attachment.results.length === 1); + t.is(attachment.results[0].title, 'serverApiClient.test.ts'); + t.is(attachment.results[0].metadata.mediaType, 'application/javascript'); + t.is(attachment.results[0].version.minorEdit, true); +}); + +test.serial('should get attachments', async t => { + const attachments = await client.contentAttachments.getAttachments({ + id: createdContentId, + }); + + t.truthy(!!attachments); + t.truthy(attachments.results.length === 1); + t.is(attachments.results[0].title, 'serverApiClient.test.ts'); + t.is(attachments.results[0].metadata.mediaType, 'application/javascript'); +}); + +test.serial('should update attachment', async t => { + const attachments = await client.contentAttachments.createOrUpdateAttachments({ + id: createdContentId, + attachments: { + file: 'testFileContent', + filename: 'serverApiClient.test.ts', + minorEdit: false, + comment: 'some changes', + contentType: 'application/javascript', + }, + }); + + createdAttachmentId = attachments.results[0].id; + + t.truthy(!!attachments); + t.truthy(attachments.results.length === 1); + t.is(attachments.results[0].title, 'serverApiClient.test.ts'); + t.is(attachments.results[0].metadata.mediaType, 'application/javascript'); + t.is(attachments.results[0].version.minorEdit, false); + t.is(attachments.results[0].version.number, 2); + t.is(attachments.results[0].version.message, 'some changes'); +}); + +test.serial('should update attachment properties', async t => { + const attachment = await client.contentAttachments.updateAttachmentProperties({ + id: createdContentId, + attachmentId: createdAttachmentId, + update: { + id: createdAttachmentId, + version: { + number: 2, + }, + title: 'serverApiClient.test.ts', + type: 'attachment', + status: 'current', + metadata: { + mediaType: 'text/plain', + }, + }, + }); + + t.truthy(!!attachment); + t.is(attachment.title, 'serverApiClient.test.ts'); + t.is(attachment.metadata.mediaType, 'text/plain'); + t.is(attachment.version.minorEdit, false); + t.is(attachment.version.number, 2); + t.is(attachment.version.message, 'some changes'); +}); + +test.serial('should update content attachment data', async t => { + const attachment = await client.contentAttachments.updateAttachmentData({ + id: createdContentId, + attachmentId: createdAttachmentId, + attachment: { + file: 'testFileContent', + filename: 'serverApiClient.test.ts', + minorEdit: true, + }, + }); + + t.truthy(!!attachment); + t.is(attachment.title, 'serverApiClient.test.ts'); + t.is(attachment.metadata.mediaType, 'video/mp2t'); + t.is(attachment.version.minorEdit, true); + t.is(attachment.version.number, 3); + t.is(attachment.version.message, undefined); +}); + +test.serial('should download content attachment', async t => { + const attachment = await client.contentAttachments.downloadAttachment({ + id: createdContentId, + attachmentId: createdAttachmentId, + }); + + t.truthy(!!attachment); + t.is(attachment.toString(), 'testFileContent'); +}); + +test.serial('should remove content', async t => { + await client.content.deleteContent({ + id: createdContentId, + }); + + t.pass(); +}); + +test.serial('should remove space', async t => { + const removedSpace = await client.space.deleteSpace({ + spaceKey: 'AUTOMATED', + }); + + t.truthy(!!removedSpace); +}); diff --git a/tests/e2e/pageCreating.test.ts b/tests/e2e/pageCreating.test.ts deleted file mode 100644 index 347d7e24..00000000 --- a/tests/e2e/pageCreating.test.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { ConfluenceClient } from '../../src'; -import test from 'ava'; - -const HOST = process.env.HOST!; -const EMAIL = process.env.EMAIL!; -const API_TOKEN = process.env.API_TOKEN!; - -let createdContentId: string; -const client = new ConfluenceClient({ - host: HOST, - telemetry: false, - authentication: { - basic: { - email: EMAIL, - apiToken: API_TOKEN, - }, - }, -}); - -test.serial('should create space', async (t) => { - const space = await client.space.createSpace({ - name: 'Auto testing software', - key: 'AUTOMATED', - }); - - t.truthy(!!space); - t.is(space.key, 'AUTOMATED'); - t.is(space.name, 'Auto testing software'); -}); - -test.serial('should create content', async (t) => { - const content = await client.content.createContent({ - title: 'Test page', - space: { - key: 'AUTOMATED', - }, - type: 'page', - body: { - view: { - value: '', - representation: 'view', - }, - }, - }); - - createdContentId = content.id; - - t.truthy(!!content); - t.is(content.type, 'page'); - t.is(content.space?.key, 'AUTOMATED'); -}); - -test.serial('should remove content', async (t) => { - await client.content.deleteContent({ - id: createdContentId, - }); - - t.pass(); -}); - -test.serial('should remove space', async (t) => { - const removedSpace = await client.space.deleteSpace({ - spaceKey: 'AUTOMATED', - }); - - t.truthy(!!removedSpace); -}); diff --git a/tests/unit/api/space.test.ts b/tests/unit/api/space.test.ts index cd60c6c6..a17984e3 100644 --- a/tests/unit/api/space.test.ts +++ b/tests/unit/api/space.test.ts @@ -4,7 +4,7 @@ import test from 'ava'; const config = { host: '' }; -test('when spaceKey is not provided', (t) => { +test('when spaceKey is not provided', t => { const client = new ConfluenceClient(config); const sendRequestStub = sinon.stub(client, 'sendRequest'); @@ -15,7 +15,7 @@ test('when spaceKey is not provided', (t) => { t.is(callArgument.params.spaceKey, undefined); }); -test('when spaceKey is empty array', (t) => { +test('when spaceKey is empty array', t => { const client = new ConfluenceClient(config); const sendRequestStub = sinon.stub(client, 'sendRequest'); @@ -26,7 +26,7 @@ test('when spaceKey is empty array', (t) => { t.is(callArgument.params.spaceKey, ''); }); -test('when spaceKey has one key', (t) => { +test('when spaceKey has one key', t => { const client = new ConfluenceClient(config); const sendRequestStub = sinon.stub(client, 'sendRequest'); @@ -37,7 +37,7 @@ test('when spaceKey has one key', (t) => { t.is(callArgument.params.spaceKey(), 'spaceKey=KEY1'); }); -test('when spaceKey has multiple keys', (t) => { +test('when spaceKey has multiple keys', t => { const client = new ConfluenceClient(config); const sendRequestStub = sinon.stub(client, 'sendRequest'); diff --git a/tests/unit/index.test.ts b/tests/unit/index.test.ts index 82b75e33..f0744cfe 100644 --- a/tests/unit/index.test.ts +++ b/tests/unit/index.test.ts @@ -8,19 +8,19 @@ import { RequestConfig, } from '../../src'; -test('Callback should be defined', (t) => { +test('Callback should be defined', t => { const callback: Callback = () => {}; t.truthy(!!callback); }); -test('RequestConfig should be defined', (t) => { +test('RequestConfig should be defined', t => { const requestConfig: RequestConfig = {}; t.truthy(!!requestConfig); }); -test('Config should be defined', (t) => { +test('Config should be defined', t => { const config: Config = { host: '', }; @@ -30,7 +30,7 @@ test('Config should be defined', (t) => { t.is(typeof config.host, 'string'); }); -test('Client should be defined', async (t) => { +test('Client should be defined', async t => { const client: Client = { sendRequest(): Promise { return Promise.resolve(undefined); @@ -42,13 +42,13 @@ test('Client should be defined', async (t) => { t.falsy(!!(await client.sendRequest({}))); }); -test('BaseClient should be defined', (t) => { +test('BaseClient should be defined', t => { const baseClient = new BaseClient({ host: '' }); t.truthy(!!baseClient); }); -test('ConfluenceClient should be defined', (t) => { +test('ConfluenceClient should be defined', t => { const confluenceClient = new ConfluenceClient({ host: '' }); t.truthy(!!confluenceClient);