From 94e77046ea79236b1b2c27cb84fa539cea492c10 Mon Sep 17 00:00:00 2001 From: Max de Groot Date: Tue, 23 Dec 2025 16:15:48 +0100 Subject: [PATCH 01/18] feat(package): Refactor package for TypeScript ESM module support --- .eslintrc.json | 3 +- package-lock.json | 345 +++++++++++++++++++++++++++++++++++++++++----- package.json | 23 +++- tsconfig.json | 18 +++ 4 files changed, 354 insertions(+), 35 deletions(-) create mode 100644 tsconfig.json diff --git a/.eslintrc.json b/.eslintrc.json index 06a4e19..0da1226 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -11,7 +11,8 @@ "SharedArrayBuffer": "readonly" }, "parserOptions": { - "ecmaVersion": 2018 + "ecmaVersion": 2018, + "sourceType": "module" }, "rules": { "indent": [ diff --git a/package-lock.json b/package-lock.json index 6a6b8d7..1317330 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "shotgun-nodejs", - "version": "4.3.0", + "version": "4.4.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "shotgun-nodejs", - "version": "4.3.0", + "version": "4.4.0", "license": "ISC", "dependencies": { "async-retry": "^1.3.3", @@ -15,7 +15,12 @@ "qs": "^6.10.5" }, "devDependencies": { - "eslint": "^8.17.0" + "@types/async-retry": "^1.4.9", + "@types/node": "^25.0.3", + "@types/node-fetch": "^2.6.13", + "@types/qs": "^6.14.0", + "eslint": "^8.17.0", + "typescript": "^5.4.5" } }, "node_modules/@eslint/eslintrc": { @@ -63,6 +68,51 @@ "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" }, + "node_modules/@types/async-retry": { + "version": "1.4.9", + "resolved": "https://registry.npmjs.org/@types/async-retry/-/async-retry-1.4.9.tgz", + "integrity": "sha512-s1ciZQJzRh3708X/m3vPExr5KJlzlZJvXsKpbtE2luqNcbROr64qU+3KpJsYHqWMeaxI839OvXf9PrUSw1Xtyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/retry": "*" + } + }, + "node_modules/@types/node": { + "version": "25.0.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.3.tgz", + "integrity": "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/node-fetch": { + "version": "2.6.13", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.13.tgz", + "integrity": "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.4" + } + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/retry": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.5.tgz", + "integrity": "sha512-3xSjTp3v03X/lSQLkczaN9UIEwJMoMCA1+Nb5HfbJEQWogdeQIyVtTvxPXDQjZ5zws8rFQfVfRdz03ARihPJgw==", + "dev": true, + "license": "MIT" + }, "node_modules/acorn": { "version": "8.7.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", @@ -138,6 +188,13 @@ "retry": "0.13.1" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -166,6 +223,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -209,6 +279,19 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -230,12 +313,13 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -252,6 +336,16 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -264,6 +358,66 @@ "node": ">=6.0.0" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -498,6 +652,23 @@ "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", "dev": true }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -505,9 +676,13 @@ "dev": true }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/functional-red-black-tree": { "version": "1.0.1", @@ -516,18 +691,42 @@ "dev": true }, "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -575,15 +774,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", "engines": { - "node": ">= 0.4.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-flag": { @@ -596,9 +796,10 @@ } }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -606,6 +807,34 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -744,6 +973,38 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -757,10 +1018,11 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" }, "node_modules/natural-compare": { "version": "1.4.0", @@ -1132,6 +1394,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", diff --git a/package.json b/package.json index ab3fcb1..0d29a95 100644 --- a/package.json +++ b/package.json @@ -8,12 +8,29 @@ "name": "shotgun-nodejs", "version": "4.4.0", "description": "Autodesk Shotgrid REST API library", - "main": "src/index.js", + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "devDependencies": { - "eslint": "^8.17.0" + "@types/async-retry": "^1.4.9", + "@types/node": "^25.0.3", + "@types/node-fetch": "^2.6.13", + "@types/qs": "^6.14.0", + "eslint": "^8.17.0", + "typescript": "^5.4.5" }, + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, + "files": ["dist"], "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "build": "tsc -p tsconfig.json", + "dev": "tsc -w -p tsconfig.json", + "prepublishOnly": "npm run build", + "test": "node --test" }, "keywords": [ "shotgrid", diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..d54527f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + + "rootDir": "src", + "outDir": "dist", + + "declaration": true, + "declarationMap": true, + "sourceMap": true, + + "strict": true, + "skipLibCheck": true + }, + "include": ["src"] +} \ No newline at end of file From e128e5f058fd45e1954dd857502c1aef88d875a1 Mon Sep 17 00:00:00 2001 From: Max de Groot Date: Tue, 23 Dec 2025 16:21:00 +0100 Subject: [PATCH 02/18] feat(client): Refactor ShotgunApiClient to TypeScript with ESM support and typed mixins --- src/apply-mixins.ts | 14 +++++ src/{client.js => client.ts} | 104 +++++++++++++++++++++-------------- 2 files changed, 78 insertions(+), 40 deletions(-) create mode 100644 src/apply-mixins.ts rename src/{client.js => client.ts} (64%) diff --git a/src/apply-mixins.ts b/src/apply-mixins.ts new file mode 100644 index 0000000..72aec5b --- /dev/null +++ b/src/apply-mixins.ts @@ -0,0 +1,14 @@ +type Ctor = new (...args: any[]) => T; + +export function WithMixins< + TBase extends Ctor, + TMixins extends Record +>(Base: TBase, mixins: TMixins) { + class Mixed extends Base {} + Object.assign(Mixed.prototype, mixins); + return Mixed as unknown as (new ( + ...args: ConstructorParameters + ) => InstanceType & { + [K in keyof TMixins]: TMixins[K]; + }); +} \ No newline at end of file diff --git a/src/client.js b/src/client.ts similarity index 64% rename from src/client.js rename to src/client.ts index 75423ca..1b6445c 100644 --- a/src/client.js +++ b/src/client.ts @@ -1,19 +1,45 @@ -const fetch = require('node-fetch'); -const qs = require('qs'); -const retry = require('async-retry'); -const util = require('util'); -const mixins = require('./client/index'); +import fetch, {Response} from 'node-fetch'; +import qs from 'qs'; +import retry from 'async-retry'; +import * as util from 'node:util'; +import mixins from './client/index.js'; -const { RequestError } = require('./error'); +import {RequestError} from './error.js'; +import {WithMixins} from "./apply-mixins.js"; const DEFAULT_API_BASE_PATH = '/api/v1'; const RETRY_COUNT = 2; -class ShotgunApiClient { +type Credentials = Record; - constructor({ siteUrl, credentials, debug, apiBasePath = DEFAULT_API_BASE_PATH }) { +type AuthToken = { + refresh_token: string; + access_token: string; + token_type: string; + [key: string]: unknown; +}; + +type RequestParams = { + method?: string; + path?: string; + headers?: Record; + query?: Record; + body?: BodyInit; + requestId?: string; + skipBasePathPrepend?: boolean; +}; +class ShotgunApiClientBase { + siteUrl: string; + credentials: Credentials; + debug?: boolean; + apiBasePath: string; + + private _token: AuthToken | null; + + constructor({ siteUrl, credentials, debug, apiBasePath = DEFAULT_API_BASE_PATH }: { siteUrl: string; credentials: Credentials; debug?: boolean; apiBasePath?: string }) { this.siteUrl = siteUrl; + this.credentials = credentials; this._token = null; this.debug = debug; @@ -24,40 +50,38 @@ class ShotgunApiClient { this.apiBasePath = apiBasePath; } - get token() { + get token(): AuthToken | null { return this._token; } - set token(val) { + set token(val: AuthToken | null) { this._token = val; } - async connect(credentials = this.credentials) { - + async connect(credentials: Credentials = this.credentials): Promise { let { siteUrl, apiBasePath } = this; let url = new URL(`${siteUrl}${apiBasePath}/auth/access_token`); - // @NOTE Should they be cleared from memory at this time? - url.search = qs.stringify(credentials); let resp = await this.fetchWithRetry(url, { method: 'POST', headers: { 'Accept': 'application/json', - } + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: qs.stringify(credentials, {}) }); if (!resp.ok) { - let respBody = await resp.text(); let errorResp = new RequestError({ respBody }); throw new Error(`Error getting connect response: ${errorResp}`); } - let body; + let body: AuthToken; try { body = await resp.json(); - } catch (err) { + } catch (err: any) { throw new Error(`Error parsing connect response: ${err.message}`); } @@ -65,8 +89,7 @@ class ShotgunApiClient { return body; } - async refreshToken() { - + async refreshToken(): Promise { let { siteUrl, apiBasePath, token } = this; if (!token) @@ -93,10 +116,10 @@ class ShotgunApiClient { throw new Error(`Error getting refresh token response: ${errorResp}`); } - let body; + let body: AuthToken; try { body = await resp.json(); - } catch (err) { + } catch (err: any) { throw new Error(`Error parsing refresh token response: ${err.message}`); } @@ -104,8 +127,7 @@ class ShotgunApiClient { return body; } - tokenExpired(token) { - + tokenExpired(token?: string): boolean { if (!token) return false; @@ -114,8 +136,7 @@ class ShotgunApiClient { return (Date.now() / 1000) > jwtPayload.exp; } - async getAuthorizationHeader() { - + async getAuthorizationHeader(): Promise { let { token } = this; if (!token || this.tokenExpired(token.refresh_token)) @@ -126,8 +147,7 @@ class ShotgunApiClient { return `${token.token_type} ${token.access_token}`; } - async requestRaw({ method = 'GET', path, headers, query, body, requestId, skipBasePathPrepend }) { - + async requestRaw({ method = 'GET', path, headers, query, body, requestId, skipBasePathPrepend }: RequestParams): Promise { let { siteUrl, apiBasePath, debug } = this; if (!path) @@ -159,12 +179,10 @@ class ShotgunApiClient { if (debug) console.log('Sending request', requestId, url.href, util.inspect({ method, headers, body }, false, Infinity, true)); - let resp = await this.fetchWithRetry(url, { method, headers, body }); - return resp; + return await this.fetchWithRetry(url, {method, headers, body}); } - async request(params) { - + async request(params: RequestParams): Promise { let { debug } = this; let { method, path } = params; @@ -187,16 +205,16 @@ class ShotgunApiClient { return respBody; } - async fetchWithRetry(...args) { - + async fetchWithRetry(...args: Parameters): Promise { let { debug } = this; + const fetchFn = this.getFetch(); return retry( async (fnBail, attemptNumber) => { if (debug) console.log(`Request attempt #${attemptNumber}`); - let resp = await fetch(...args); + let resp = await fetchFn(...args); if (attemptNumber <= RETRY_COUNT && (resp.status >= 500 || resp.status === 0)) { throw new Error('Force-trigger retry'); } @@ -207,13 +225,19 @@ class ShotgunApiClient { } ); } + + getFetch(): (input: unknown, init?: unknown) => Promise { + if (typeof globalThis.fetch === 'function') { + return globalThis.fetch.bind(globalThis) as (input: unknown, init?: unknown) => Promise; + } + + throw new Error('Fetch API is not available. Provide a global fetch implementation.'); + } } -// We remove require-all from dependencies as the were using fs -// that is not supported in the browser. -Object.assign(ShotgunApiClient.prototype, mixins); +class ShotgunApiClient extends WithMixins(ShotgunApiClientBase, mixins) {} -module.exports = { - default: ShotgunApiClient, +export default ShotgunApiClient; +export { ShotgunApiClient, }; From 6d19cb2aea7460a479d3b0f02994ec7a99d70385 Mon Sep 17 00:00:00 2001 From: Max de Groot Date: Tue, 23 Dec 2025 16:22:43 +0100 Subject: [PATCH 03/18] feat(client): Add grant type handling for credentials in ShotgunApiClient --- src/client.ts | 51 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/src/client.ts b/src/client.ts index 1b6445c..02dec4c 100644 --- a/src/client.ts +++ b/src/client.ts @@ -10,7 +10,33 @@ import {WithMixins} from "./apply-mixins.js"; const DEFAULT_API_BASE_PATH = '/api/v1'; const RETRY_COUNT = 2; -type Credentials = Record; +enum GrantType { + ClientCredentials = 'client_credentials', + PasswordCredentials = 'password', + SessionCredentials = 'session_token', + RefreshCredentials = 'refresh', +} +type ClientCredentials = { + client_id: string; + client_secret: string; + scope?: string; + session_uuid?: string; +}; +type PasswordCredentials = { + username: string; + password: string; + auth_token?: string; + scope?: string; + session_uuid?: string; +}; +type SessionCredentials = { + session_token: string; +} +type RefreshCredentials = { + refresh_token: string; +} + +type Credentials = ClientCredentials | PasswordCredentials | SessionCredentials | RefreshCredentials; type AuthToken = { refresh_token: string; @@ -35,12 +61,27 @@ class ShotgunApiClientBase { debug?: boolean; apiBasePath: string; + private readonly _grant_type: GrantType; private _token: AuthToken | null; constructor({ siteUrl, credentials, debug, apiBasePath = DEFAULT_API_BASE_PATH }: { siteUrl: string; credentials: Credentials; debug?: boolean; apiBasePath?: string }) { this.siteUrl = siteUrl; this.credentials = credentials; + this._grant_type = GrantType.ClientCredentials; + if ("client_id" in credentials || "client_secret" in credentials) { + this._grant_type = GrantType.ClientCredentials; + } + else if ("username" in credentials || "password" in credentials) { + this._grant_type = GrantType.PasswordCredentials; + } + else if ("session_token" in credentials) { + this._grant_type = GrantType.SessionCredentials; + } + else if ("refresh_token" in credentials) { + this._grant_type = GrantType.RefreshCredentials; + } + this._token = null; this.debug = debug; @@ -69,7 +110,10 @@ class ShotgunApiClientBase { 'Accept': 'application/json', 'Content-Type': 'application/x-www-form-urlencoded', }, - body: qs.stringify(credentials, {}) + body: qs.stringify({ + ...credentials, + 'grant_type': this._grant_type + }, {}) }); if (!resp.ok) { @@ -98,7 +142,7 @@ class ShotgunApiClientBase { let url = new URL(`${siteUrl}${apiBasePath}/auth/access_token`); url.search = qs.stringify({ refresh_token: token.refresh_token, - grant_type: 'refresh', + grant_type: GrantType.RefreshCredentials, }); let resp = await this.fetchWithRetry(url, { @@ -241,3 +285,4 @@ export default ShotgunApiClient; export { ShotgunApiClient, }; + From d447ced699c475c1a1d50f9d8c6781b4e0f95487 Mon Sep 17 00:00:00 2001 From: Max de Groot Date: Tue, 23 Dec 2025 16:22:47 +0100 Subject: [PATCH 04/18] feat(client): Add grant type handling for credentials in ShotgunApiClient --- src/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client.ts b/src/client.ts index 02dec4c..e34749a 100644 --- a/src/client.ts +++ b/src/client.ts @@ -7,7 +7,7 @@ import mixins from './client/index.js'; import {RequestError} from './error.js'; import {WithMixins} from "./apply-mixins.js"; -const DEFAULT_API_BASE_PATH = '/api/v1'; +const DEFAULT_API_BASE_PATH = '/api/v1.1'; const RETRY_COUNT = 2; enum GrantType { From 3633c6a3c4b9e789dc66c0b659097951b5912d7f Mon Sep 17 00:00:00 2001 From: Max de Groot Date: Tue, 23 Dec 2025 16:22:58 +0100 Subject: [PATCH 05/18] refactor(core): Migrate index.js to TypeScript with ESM support --- src/index.js | 13 ------------- src/index.ts | 13 +++++++++++++ 2 files changed, 13 insertions(+), 13 deletions(-) delete mode 100644 src/index.js create mode 100644 src/index.ts diff --git a/src/index.js b/src/index.js deleted file mode 100644 index 2ca8262..0000000 --- a/src/index.js +++ /dev/null @@ -1,13 +0,0 @@ -const { ErrorResponse, RequestError } = require('./error'); -const { PaginatedRecordResponse } = require('./paginated-record-response'); -const { SchemaFieldDefinition } = require('./schema-field-definition'); -const { ShotgunApiClient } = require('./client'); - -module.exports = { - default: ShotgunApiClient, - ErrorResponse, - PaginatedRecordResponse, - RequestError, - SchemaFieldDefinition, - ShotgunApiClient, -}; diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..bae6027 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,13 @@ +import { ErrorResponse, RequestError } from './error.js'; +import { PaginatedRecordResponse } from './paginated-record-response.js'; +import { SchemaFieldDefinition } from './schema-field-definition.js'; +import { ShotgunApiClient } from './client.js'; + +export default ShotgunApiClient; +export { + ErrorResponse, + PaginatedRecordResponse, + RequestError, + SchemaFieldDefinition, + ShotgunApiClient, +}; From 4b84d037d6dd82122444d210582955418913c40e Mon Sep 17 00:00:00 2001 From: Max de Groot Date: Tue, 23 Dec 2025 16:23:11 +0100 Subject: [PATCH 06/18] refactor(client): Migrate client index.js to TypeScript with ESM support --- src/client/index.js | 33 ---------------------------- src/client/index.ts | 52 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 33 deletions(-) delete mode 100644 src/client/index.js create mode 100644 src/client/index.ts diff --git a/src/client/index.js b/src/client/index.js deleted file mode 100644 index 7cc9fb0..0000000 --- a/src/client/index.js +++ /dev/null @@ -1,33 +0,0 @@ -const entityBatch = require('./entity-batch'); -const entityCreate = require('./entity-create'); -const entityDelete = require('./entity-delete'); -const entityItemUpload = require('./entity-item-upload'); -const entityRead = require('./entity-read'); -const entityReadAll = require('./entity-read-all'); -const entityRevive = require('./entity-revive'); -const entitySearch = require('./entity-search'); -const entityUpdate = require('./entity-update'); -const preferencesGet = require('./preferences-get'); -const schemaFieldCreate = require('./schema-field-create'); -const schemaFieldDelete = require('./schema-field-delete'); -const schemaFieldRevive = require('./schema-field-revive'); -const schemaFieldUpdate = require('./schema-field-update'); -const schemaGet = require('./schema-get'); - -module.exports = { - entityBatch, - entityCreate, - entityDelete, - entityItemUpload, - entityRead, - entityReadAll, - entityRevive, - entitySearch, - entityUpdate, - preferencesGet, - schemaFieldCreate, - schemaFieldDelete, - schemaFieldRevive, - schemaFieldUpdate, - schemaGet, -}; diff --git a/src/client/index.ts b/src/client/index.ts new file mode 100644 index 0000000..a1b4c7b --- /dev/null +++ b/src/client/index.ts @@ -0,0 +1,52 @@ +import entityBatch from './entity-batch.js'; +import entityCreate from './entity-create.js'; +import entityDelete from './entity-delete.js'; +import entityItemUpload from './entity-item-upload.js'; +import entityRead from './entity-read.js'; +import entityReadAll from './entity-read-all.js'; +import entityRevive from './entity-revive.js'; +import entitySearch from './entity-search.js'; +import entityUpdate from './entity-update.js'; +import preferencesGet from './preferences-get.js'; +import schemaFieldCreate from './schema-field-create.js'; +import schemaFieldDelete from './schema-field-delete.js'; +import schemaFieldRevive from './schema-field-revive.js'; +import schemaFieldUpdate from './schema-field-update.js'; +import schemaGet from './schema-get.js'; + +const mixins = { + entityBatch, + entityCreate, + entityDelete, + entityItemUpload, + entityRead, + entityReadAll, + entityRevive, + entitySearch, + entityUpdate, + preferencesGet, + schemaFieldCreate, + schemaFieldDelete, + schemaFieldRevive, + schemaFieldUpdate, + schemaGet, +}; + +export default mixins; +export { + entityBatch, + entityCreate, + entityDelete, + entityItemUpload, + entityRead, + entityReadAll, + entityRevive, + entitySearch, + entityUpdate, + preferencesGet, + schemaFieldCreate, + schemaFieldDelete, + schemaFieldRevive, + schemaFieldUpdate, + schemaGet, +}; \ No newline at end of file From ec482f9f59df0155fe632f07730f892c2b17dc7b Mon Sep 17 00:00:00 2001 From: Max de Groot Date: Tue, 23 Dec 2025 16:23:19 +0100 Subject: [PATCH 07/18] refactor(core): Migrate schema-field-definition.js to TypeScript with ESM support --- ...finition.js => schema-field-definition.ts} | 75 +++++++++++-------- 1 file changed, 42 insertions(+), 33 deletions(-) rename src/{schema-field-definition.js => schema-field-definition.ts} (60%) diff --git a/src/schema-field-definition.js b/src/schema-field-definition.ts similarity index 60% rename from src/schema-field-definition.js rename to src/schema-field-definition.ts index f740487..219e09b 100644 --- a/src/schema-field-definition.js +++ b/src/schema-field-definition.ts @@ -1,25 +1,57 @@ +type SchemaProperty = { + property_name: string; + value: unknown; +}; + +type SchemaFieldDefinitionBody = { + data_type: string; + properties: SchemaProperty[] | Record; +}; + class SchemaFieldDefinition { + static DATA_TYPES = [ + 'calculated', + 'checkbox', + 'currency', + 'date', + 'date_time', + 'duration', + 'entity', + 'float', + 'footage', + 'list', + 'multi_entity', + 'number', + 'percent', + 'status_list', + 'text', + 'timecode', + 'url', + 'uuid', + ]; + + dataType?: string; + properties: Record; - constructor(body) { + constructor(body?: SchemaFieldDefinitionBody) { + this.properties = {}; if (!body) return; let { data_type, properties } = body; - this.properties = {}; this.setDataType(data_type); this.setProperties(properties); } - setDataType(dataType) { - if (!this.constructor.DATA_TYPES.includes(dataType)) + setDataType(dataType: string): void { + if (!SchemaFieldDefinition.DATA_TYPES.includes(dataType)) throw new Error(`Invalid data type '${dataType}'`); this.dataType = dataType; } - setProperties(properties) { - + setProperties(properties: SchemaProperty[] | Record): void { if (Array.isArray(properties)) { for (let p of properties) { this.properties[p.property_name] = p.value; @@ -35,10 +67,9 @@ class SchemaFieldDefinition { throw new Error('Invalid property input'); } - toBody() { - + toBody(): { data_type: string | undefined; properties: SchemaProperty[], project_id?: number } { let data_type = this.dataType; - let properties = []; + let properties: SchemaProperty[] = []; for (let k in this.properties) { properties.push({ property_name: k, @@ -53,29 +84,7 @@ class SchemaFieldDefinition { } } -SchemaFieldDefinition.DATA_TYPES = [ - 'calculated', - 'checkbox', - 'currency', - 'date', - 'date_time', - 'duration', - 'entity', - 'float', - 'footage', - 'list', - 'multi_entity', - 'number', - 'percent', - 'status_list', - 'text', - 'timecode', - 'url', - 'uuid', -]; - -module.exports = { - default: SchemaFieldDefinition, +export default SchemaFieldDefinition; +export { SchemaFieldDefinition, }; - From d616416dbcafca827023af6563fe7e6404e2bd93 Mon Sep 17 00:00:00 2001 From: Max de Groot Date: Tue, 23 Dec 2025 16:23:26 +0100 Subject: [PATCH 08/18] refactor(core): Migrate paginated-record-response.js to TypeScript with ESM support --- src/paginated-record-response.js | 48 ------------------------ src/paginated-record-response.ts | 64 ++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 48 deletions(-) delete mode 100644 src/paginated-record-response.js create mode 100644 src/paginated-record-response.ts diff --git a/src/paginated-record-response.js b/src/paginated-record-response.js deleted file mode 100644 index 252d4d0..0000000 --- a/src/paginated-record-response.js +++ /dev/null @@ -1,48 +0,0 @@ -class PaginatedRecordResponse { - - constructor({ data, links, _pageSize }) { - this.data = data; - this.links = links || {}; - this.pageSize = _pageSize; - } - - reachedEnd() { - return this.data.length !== this.pageSize; - } - - async getNext({ client }) { - - let path = this.links.next; - return this._get({ path, client }); - } - - async getPrev({ client }) { - - let path = this.links.prev; - return this._get({ path, client }); - } - - async _get({ path, client }) { - - if (!path) - return; - - let out = new this.constructor(await client.request({ - path, - skipBasePathPrepend: true - })); - - // Inherit page size - out.pageSize = this.pageSize; - - if (!out.data.length) - return; - - return out; - } -} - -module.exports = { - default: PaginatedRecordResponse, - PaginatedRecordResponse, -}; diff --git a/src/paginated-record-response.ts b/src/paginated-record-response.ts new file mode 100644 index 0000000..1b53808 --- /dev/null +++ b/src/paginated-record-response.ts @@ -0,0 +1,64 @@ +type PaginatedLinks = { + next?: string; + prev?: string; + [key: string]: string | undefined; +}; + +type PaginatedRecordParams = { + data: T[]; + links?: PaginatedLinks; + _pageSize?: number; +}; + +type RequestClient = { + request: (params: { path: string; skipBasePathPrepend?: boolean }) => Promise>; +}; + +class PaginatedRecordResponse { + data: T[]; + links: PaginatedLinks; + pageSize?: number; + + constructor({ data, links, _pageSize }: PaginatedRecordParams) { + this.data = data; + this.links = links || {}; + this.pageSize = _pageSize; + } + + reachedEnd(): boolean { + return this.data.length !== this.pageSize; + } + + async getNext({ client }: { client: RequestClient }): Promise | undefined> { + let path = this.links.next; + return this._get({ path, client }); + } + + async getPrev({ client }: { client: RequestClient }): Promise | undefined> { + let path = this.links.prev; + return this._get({ path, client }); + } + + async _get({ path, client }: { path?: string; client: RequestClient }): Promise | undefined> { + if (!path) + return; + + let out = new PaginatedRecordResponse(await client.request({ + path, + skipBasePathPrepend: true + }) as PaginatedRecordParams); + + // Inherit page size + out.pageSize = this.pageSize; + + if (!out.data.length) + return; + + return out; + } +} + +export default PaginatedRecordResponse; +export { + PaginatedRecordResponse, +}; From 2d89f728bfedb5633c503923cba8b79ca32a507a Mon Sep 17 00:00:00 2001 From: Max de Groot Date: Tue, 23 Dec 2025 16:23:34 +0100 Subject: [PATCH 09/18] refactor(core): Migrate error.js to TypeScript with ESM support --- src/error.js | 47 ------------------------------- src/error.ts | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 47 deletions(-) delete mode 100644 src/error.js create mode 100644 src/error.ts diff --git a/src/error.js b/src/error.js deleted file mode 100644 index 95061fc..0000000 --- a/src/error.js +++ /dev/null @@ -1,47 +0,0 @@ -class ErrorResponse { - constructor({ errors } = {}) { - if (!errors) errors = []; - this.errors = errors.map(err => new ErrorObject(err)); - } - - toString() { - return this.errors.map(err => `${err.title} (Code ${err.code})`).join('; '); - } -} - -class ErrorObject { - constructor({ id, status, code, title, detail, source, meta } = {}) { - this.id = id; - this.status = status; - this.code = code; - this.title = title; - this.detail = detail; - this.source = source; - this.meta = meta; - } -} - -class RequestError extends Error { - - constructor({ message, method, path, respBody, resp }) { - - let simpleMessage = 'Error performing request'; - if (method) simpleMessage += ' ' + method; - if (path) simpleMessage += ' ' + path; - - if (!message) { - message = simpleMessage; - if (respBody) message += ': ' + JSON.stringify(respBody); - } - super(message); - - this.simpleMessage = simpleMessage; - this.body = respBody; - this.resp = resp; - } -} - -module.exports = { - ErrorResponse, - RequestError, -}; diff --git a/src/error.ts b/src/error.ts new file mode 100644 index 0000000..5f29be3 --- /dev/null +++ b/src/error.ts @@ -0,0 +1,78 @@ +import { Response } from 'node-fetch'; + +type ErrorObjectInput = { + id?: string; + status?: string | number; + code?: string | number; + title?: string; + detail?: string; + source?: unknown; + meta?: unknown; +}; + +class ErrorResponse { + errors: ErrorObject[]; + + constructor({ errors }: { errors?: ErrorObjectInput[] } = {}) { + this.errors = (errors ?? []).map(err => new ErrorObject(err)); + } + + toString(): string { + return this.errors.map(err => `${err.title} (Code ${err.code})`).join('; '); + } +} + +class ErrorObject { + id?: string; + status?: string | number; + code?: string | number; + title?: string; + detail?: string; + source?: unknown; + meta?: unknown; + + constructor({ id, status, code, title, detail, source, meta }: ErrorObjectInput = {}) { + this.id = id; + this.status = status; + this.code = code; + this.title = title; + this.detail = detail; + this.source = source; + this.meta = meta; + } +} + +type RequestErrorInput = { + message?: string; + method?: string; + path?: string; + respBody?: unknown; + resp?: Response; +}; + +class RequestError extends Error { + simpleMessage: string; + body: unknown; + resp?: Response; + + constructor({ message, method, path, respBody, resp }: RequestErrorInput) { + let simpleMessage = 'Error performing request'; + if (method) simpleMessage += ' ' + method; + if (path) simpleMessage += ' ' + path; + + if (!message) { + message = simpleMessage; + if (respBody) message += ': ' + JSON.stringify(respBody); + } + super(message); + + this.simpleMessage = simpleMessage; + this.body = respBody; + this.resp = resp; + } +} + +export { + ErrorResponse, + RequestError, +}; \ No newline at end of file From 37afbc393721434bf15fe9a8b481859564d10916 Mon Sep 17 00:00:00 2001 From: Max de Groot Date: Tue, 23 Dec 2025 16:24:23 +0100 Subject: [PATCH 10/18] refactor(client): Migrate client mixins to TypeScript with ESM support --- .../{entity-batch.js => entity-batch.ts} | 8 +++-- .../{entity-create.js => entity-create.ts} | 8 +++-- .../{entity-delete.js => entity-delete.ts} | 8 +++-- ...y-item-upload.js => entity-item-upload.ts} | 29 ++++++++++++++----- ...{entity-read-all.js => entity-read-all.ts} | 12 ++++---- src/client/{entity-read.js => entity-read.ts} | 10 ++++--- .../{entity-revive.js => entity-revive.ts} | 8 +++-- .../{entity-search.js => entity-search.ts} | 12 ++++---- .../{entity-update.js => entity-update.ts} | 8 +++-- ...{preferences-get.js => preferences-get.ts} | 8 +++-- ...field-create.js => schema-field-create.ts} | 10 ++++--- ...field-delete.js => schema-field-delete.ts} | 8 +++-- ...field-revive.js => schema-field-revive.ts} | 8 +++-- ...field-update.js => schema-field-update.ts} | 10 ++++--- src/client/{schema-get.js => schema-get.ts} | 10 ++++--- 15 files changed, 99 insertions(+), 58 deletions(-) rename src/client/{entity-batch.js => entity-batch.ts} (65%) rename src/client/{entity-create.js => entity-create.ts} (60%) rename src/client/{entity-delete.js => entity-delete.ts} (62%) rename src/client/{entity-item-upload.js => entity-item-upload.ts} (63%) rename src/client/{entity-read-all.js => entity-read-all.ts} (71%) rename src/client/{entity-read.js => entity-read.ts} (67%) rename src/client/{entity-revive.js => entity-revive.ts} (64%) rename src/client/{entity-search.js => entity-search.ts} (73%) rename src/client/{entity-update.js => entity-update.ts} (62%) rename src/client/{preferences-get.js => preferences-get.ts} (67%) rename src/client/{schema-field-create.js => schema-field-create.ts} (61%) rename src/client/{schema-field-delete.js => schema-field-delete.ts} (62%) rename src/client/{schema-field-revive.js => schema-field-revive.ts} (63%) rename src/client/{schema-field-update.js => schema-field-update.ts} (66%) rename src/client/{schema-get.js => schema-get.ts} (72%) diff --git a/src/client/entity-batch.js b/src/client/entity-batch.ts similarity index 65% rename from src/client/entity-batch.js rename to src/client/entity-batch.ts index 1e30c4d..4ea1f38 100644 --- a/src/client/entity-batch.js +++ b/src/client/entity-batch.ts @@ -4,8 +4,7 @@ * @param {Object} options.requests - List of requests to batch. * @return {Object[]} Mapped request results. */ -const entityBatch = async function({ requests }) { - +const entityBatch = async function(this: any, { requests }: { requests: unknown[] }): Promise { let body = { requests }; @@ -18,4 +17,7 @@ const entityBatch = async function({ requests }) { return respBody.data; }; -module.exports = entityBatch; \ No newline at end of file +export default entityBatch; +export { + entityBatch, +}; diff --git a/src/client/entity-create.js b/src/client/entity-create.ts similarity index 60% rename from src/client/entity-create.js rename to src/client/entity-create.ts index beea0fc..c3c00d6 100644 --- a/src/client/entity-create.js +++ b/src/client/entity-create.ts @@ -5,8 +5,7 @@ * @param {Object} options.data - Entity data. * @return {Object} Created entity. */ -const entityCreate = async function({ entity, data }) { - +const entityCreate = async function(this: any, { entity, data }: { entity: string; data: Record }): Promise { let respBody = await this.request({ method: 'POST', path: `/entity/${entity}`, @@ -15,4 +14,7 @@ const entityCreate = async function({ entity, data }) { return respBody.data; }; -module.exports = entityCreate; \ No newline at end of file +export default entityCreate; +export { + entityCreate, +}; diff --git a/src/client/entity-delete.js b/src/client/entity-delete.ts similarity index 62% rename from src/client/entity-delete.js rename to src/client/entity-delete.ts index c03c6a2..a39d2ce 100644 --- a/src/client/entity-delete.js +++ b/src/client/entity-delete.ts @@ -5,8 +5,7 @@ * @param {number} options.entityId - Target entity ID. * @return {Object} Request result. */ -const entityDelete = async function({ entity, entityId }) { - +const entityDelete = async function(this: any, { entity, entityId }: { entity: string; entityId: number }): Promise { let respBody = await this.request({ method: 'DELETE', path: `/entity/${entity}/${entityId}`, @@ -14,4 +13,7 @@ const entityDelete = async function({ entity, entityId }) { return respBody; }; -module.exports = entityDelete; \ No newline at end of file +export default entityDelete; +export { + entityDelete, +}; diff --git a/src/client/entity-item-upload.js b/src/client/entity-item-upload.ts similarity index 63% rename from src/client/entity-item-upload.js rename to src/client/entity-item-upload.ts index bfb574b..c9e56bf 100644 --- a/src/client/entity-item-upload.js +++ b/src/client/entity-item-upload.ts @@ -1,4 +1,5 @@ -const fileType = require('file-type'); +import fetch from 'node-fetch'; +import { fromBuffer } from 'file-type'; /** * Upload an entity item @@ -11,7 +12,9 @@ const fileType = require('file-type'); * @param {string[]} [options.additionalUploadData] - File metadata. * @return {Object} Request information. */ -const entityItemUpload = async function({ entity, entityId, fieldName, targetFileName, uploadFileBlob, additionalUploadData = {} }) { +type UploadFileBlob = Buffer & { type?: string; size?: number }; + +const entityItemUpload = async function(this: any, { entity, entityId, fieldName, targetFileName, uploadFileBlob, additionalUploadData = {} }: { entity: string; entityId: number; fieldName?: string; targetFileName: string; uploadFileBlob: UploadFileBlob; additionalUploadData?: Record }) { let path = `/entity/${entity}/${entityId}`; if (fieldName) path += `/${fieldName}`; @@ -26,7 +29,8 @@ const entityItemUpload = async function({ entity, entityId, fieldName, targetFil // Sanity: NodeJS Buffer to Blob if (uploadFileBlob instanceof Buffer) { - uploadFileBlob.type = fileType(uploadFileBlob).mime; + const fileInfo = await fromBuffer(uploadFileBlob); + uploadFileBlob.type = fileInfo?.mime ?? uploadFileBlob.type; uploadFileBlob.size = uploadFileBlob.length; } @@ -43,14 +47,20 @@ const entityItemUpload = async function({ entity, entityId, fieldName, targetFil console.log('PUT file', uploadUrl.href, uploadFileBlob.type, uploadFileBlob.size); } + if (typeof globalThis.fetch !== 'function') { + throw new Error('Fetch API is not available. Provide a global fetch implementation.'); + } + + const fetchFn = globalThis.fetch.bind(globalThis); + // Upload file - let uploadResp = await fetch(uploadUrl, { + let uploadResp = await fetchFn(uploadUrl, { method: 'PUT', headers: { - 'Content-Type': uploadFileBlob.type, - 'Content-Size': uploadFileBlob.size + 'Content-Type': uploadFileBlob.type || 'application/octet-stream', + 'Content-Size': uploadFileBlob.size?.toString() ?? "" }, - body: uploadFileBlob, + body: uploadFileBlob as unknown as Blob, // Ignore type and size }); if (!uploadResp.ok) { @@ -71,4 +81,7 @@ const entityItemUpload = async function({ entity, entityId, fieldName, targetFil }); }; -module.exports = entityItemUpload; \ No newline at end of file +export default entityItemUpload; +export { + entityItemUpload, +}; diff --git a/src/client/entity-read-all.js b/src/client/entity-read-all.ts similarity index 71% rename from src/client/entity-read-all.js rename to src/client/entity-read-all.ts index 048c742..88dda75 100644 --- a/src/client/entity-read-all.js +++ b/src/client/entity-read-all.ts @@ -1,4 +1,4 @@ -const { PaginatedRecordResponse } = require('../paginated-record-response'); +import { PaginatedRecordResponse } from '../paginated-record-response.js'; /** * Read multiple entities. @@ -12,9 +12,8 @@ const { PaginatedRecordResponse } = require('../paginated-record-response'); * @param {Object} [options.options] - Request option settings. * @return {PaginatedRecordResponse} Targered partial response. */ -const entityReadAll = async function({ entity, filter, fields, sort, pageSize, pageNumber, options }) { - - let query = { +const entityReadAll = async function(this: any, { entity, filter, fields, sort, pageSize, pageNumber, options }: { entity: string; filter?: Record; fields?: string[] | string; sort?: string[] | string; pageSize?: number; pageNumber?: number; options?: Record }): Promise { + let query: Record = { page: { size: pageSize || 500, number: pageNumber || 1, @@ -50,4 +49,7 @@ const entityReadAll = async function({ entity, filter, fields, sort, pageSize, p return new PaginatedRecordResponse(respBody); }; -module.exports = entityReadAll; \ No newline at end of file +export default entityReadAll; +export { + entityReadAll, +}; diff --git a/src/client/entity-read.js b/src/client/entity-read.ts similarity index 67% rename from src/client/entity-read.js rename to src/client/entity-read.ts index e8a133b..47b9103 100644 --- a/src/client/entity-read.js +++ b/src/client/entity-read.ts @@ -7,9 +7,8 @@ * @param {Object} [options.options] - Request option settings. * @return {Object} Entity information. */ -const entityRead = async function({ entity, entityId, fields, options }) { - - let query = {}; +const entityRead = async function(this: any, { entity, entityId, fields, options }: { entity: string; entityId: number; fields?: string[] | string; options?: Record }): Promise { + let query: Record = {}; if (Array.isArray(fields)) fields = fields.join(','); @@ -28,4 +27,7 @@ const entityRead = async function({ entity, entityId, fields, options }) { return respBody.data; }; -module.exports = entityRead ; \ No newline at end of file +export default entityRead; +export { + entityRead, +}; diff --git a/src/client/entity-revive.js b/src/client/entity-revive.ts similarity index 64% rename from src/client/entity-revive.js rename to src/client/entity-revive.ts index 4836c02..a9b93eb 100644 --- a/src/client/entity-revive.js +++ b/src/client/entity-revive.ts @@ -5,8 +5,7 @@ * @param {number} options.entityId - Target entity ID. * @return {Object} Revived entity. */ -const entityRevive = async function({ entity, entityId }) { - +const entityRevive = async function(this: any, { entity, entityId }: { entity: string; entityId: number }): Promise { let respBody = await this.request({ method: 'POST', path: `/entity/${entity}/${entityId}`, @@ -17,4 +16,7 @@ const entityRevive = async function({ entity, entityId }) { return respBody.data; }; -module.exports = entityRevive; \ No newline at end of file +export default entityRevive; +export { + entityRevive, +}; diff --git a/src/client/entity-search.js b/src/client/entity-search.ts similarity index 73% rename from src/client/entity-search.js rename to src/client/entity-search.ts index 22ad247..6d9617d 100644 --- a/src/client/entity-search.js +++ b/src/client/entity-search.ts @@ -1,4 +1,4 @@ -const { PaginatedRecordResponse } = require('../paginated-record-response'); +import { PaginatedRecordResponse } from '../paginated-record-response.js'; /** * Query entities with complex filters. @@ -13,9 +13,8 @@ const { PaginatedRecordResponse } = require('../paginated-record-response'); * @param {number} [options.pageNumber] - Position in list of items to start querying from. * @return {PaginatedRecordResponse} Query results. */ -const entitySearch = async function({ entity, filters, fields, sort, pageSize, pageNumber }) { - - let query = { +const entitySearch = async function(this: any, { entity, filters, fields, sort, pageSize, pageNumber }: { entity: string; filters: Record | unknown[]; fields?: string[] | string; sort?: string[] | string; pageSize?: number; pageNumber?: number }): Promise { + let query: Record = { page: { size: pageSize || 500, number: pageNumber || 1, @@ -49,4 +48,7 @@ const entitySearch = async function({ entity, filters, fields, sort, pageSize, p return new PaginatedRecordResponse(respBody); }; -module.exports = entitySearch; \ No newline at end of file +export default entitySearch; +export { + entitySearch, +}; diff --git a/src/client/entity-update.js b/src/client/entity-update.ts similarity index 62% rename from src/client/entity-update.js rename to src/client/entity-update.ts index c96084e..2ea4a26 100644 --- a/src/client/entity-update.js +++ b/src/client/entity-update.ts @@ -6,8 +6,7 @@ * @param {Object} options.data - Entity data. * @return {Object} Updated entity. */ -const entityUpdate = async function({ entity, entityId, data }) { - +const entityUpdate = async function(this: any, { entity, entityId, data }: { entity: string; entityId: number; data: Record }): Promise { let respBody = await this.request({ method: 'PUT', path: `/entity/${entity}/${entityId}`, @@ -16,4 +15,7 @@ const entityUpdate = async function({ entity, entityId, data }) { return respBody.data; }; -module.exports = entityUpdate; \ No newline at end of file +export default entityUpdate; +export { + entityUpdate, +}; diff --git a/src/client/preferences-get.js b/src/client/preferences-get.ts similarity index 67% rename from src/client/preferences-get.js rename to src/client/preferences-get.ts index 800773b..49b95de 100644 --- a/src/client/preferences-get.js +++ b/src/client/preferences-get.ts @@ -4,8 +4,7 @@ * @param {string} options.names - List of preference names. * @return {Object} Hash table of preferences. */ -const preferencesGet = async function({ names }) { - +const preferencesGet = async function(this: any, { names }: { names: string[] | string }): Promise> { if (!Array.isArray(names)) names = [names]; names = names.filter(Boolean).join(','); @@ -21,4 +20,7 @@ const preferencesGet = async function({ names }) { return respBody.data; }; -module.exports = preferencesGet; \ No newline at end of file +export default preferencesGet; +export { + preferencesGet, +}; diff --git a/src/client/schema-field-create.js b/src/client/schema-field-create.ts similarity index 61% rename from src/client/schema-field-create.js rename to src/client/schema-field-create.ts index ee700d3..e273901 100644 --- a/src/client/schema-field-create.js +++ b/src/client/schema-field-create.ts @@ -1,4 +1,4 @@ -const { SchemaFieldDefinition } = require('../schema-field-definition'); +import { SchemaFieldDefinition } from '../schema-field-definition.js'; /** * Create an entity schema field. @@ -7,8 +7,7 @@ const { SchemaFieldDefinition } = require('../schema-field-definition'); * @param {SchemaFieldDefinition} options.schemaFieldDefinition - Field definition. * @return {Object} Schema (fields) definition. */ -const schemaFieldCreate = async function({ entity, schemaFieldDefinition }) { - +const schemaFieldCreate = async function(this: any, { entity, schemaFieldDefinition }: { entity: string; schemaFieldDefinition: SchemaFieldDefinition | ConstructorParameters[0] }): Promise { if (!(schemaFieldDefinition instanceof SchemaFieldDefinition)) schemaFieldDefinition = new SchemaFieldDefinition(schemaFieldDefinition); @@ -22,4 +21,7 @@ const schemaFieldCreate = async function({ entity, schemaFieldDefinition }) { return respBody.data; }; -module.exports = schemaFieldCreate; \ No newline at end of file +export default schemaFieldCreate; +export { + schemaFieldCreate, +}; diff --git a/src/client/schema-field-delete.js b/src/client/schema-field-delete.ts similarity index 62% rename from src/client/schema-field-delete.js rename to src/client/schema-field-delete.ts index e680a07..a2092ac 100644 --- a/src/client/schema-field-delete.js +++ b/src/client/schema-field-delete.ts @@ -5,8 +5,7 @@ * @param {string} options.fieldName - Target field name. * @return {Object} Operation response data. */ -const schemaFieldDelete = async function({ entity, fieldName }) { - +const schemaFieldDelete = async function(this: any, { entity, fieldName }: { entity: string; fieldName: string }): Promise { let respBody = await this.request({ method: 'DELETE', path: `/schema/${entity}/fields/${fieldName}`, @@ -14,4 +13,7 @@ const schemaFieldDelete = async function({ entity, fieldName }) { return respBody; }; -module.exports = schemaFieldDelete; \ No newline at end of file +export default schemaFieldDelete; +export { + schemaFieldDelete, +}; diff --git a/src/client/schema-field-revive.js b/src/client/schema-field-revive.ts similarity index 63% rename from src/client/schema-field-revive.js rename to src/client/schema-field-revive.ts index b9b0bde..2a6dd8f 100644 --- a/src/client/schema-field-revive.js +++ b/src/client/schema-field-revive.ts @@ -5,8 +5,7 @@ * @param {string} options.fieldName - Target field name. * @return {Object} Operation response data. */ -const schemaFieldRevive = async function({ entity, fieldName }) { - +const schemaFieldRevive = async function(this: any, { entity, fieldName }: { entity: string; fieldName: string }): Promise { let respBody = await this.request({ method: 'POST', path: `/schema/${entity}/fields/${fieldName}?revive=true`, @@ -14,4 +13,7 @@ const schemaFieldRevive = async function({ entity, fieldName }) { return respBody; }; -module.exports = schemaFieldRevive; +export default schemaFieldRevive; +export { + schemaFieldRevive, +}; diff --git a/src/client/schema-field-update.js b/src/client/schema-field-update.ts similarity index 66% rename from src/client/schema-field-update.js rename to src/client/schema-field-update.ts index 7ffe6e4..769a741 100644 --- a/src/client/schema-field-update.js +++ b/src/client/schema-field-update.ts @@ -1,4 +1,4 @@ -const { SchemaFieldDefinition } = require('../schema-field-definition'); +import { SchemaFieldDefinition } from '../schema-field-definition.js'; /** * Update an entity schema field. @@ -9,8 +9,7 @@ const { SchemaFieldDefinition } = require('../schema-field-definition'); * @param {number} [options.project] - Associated project. * @return {Object} Operation response data. */ -const schemaFieldUpdate = async function({ entity, fieldName, schemaFieldDefinition, projectId }) { - +const schemaFieldUpdate = async function(this: any, { entity, fieldName, schemaFieldDefinition, projectId }: { entity: string; fieldName: string; schemaFieldDefinition: SchemaFieldDefinition | ConstructorParameters[0]; projectId?: number }) { if (!(schemaFieldDefinition instanceof SchemaFieldDefinition)) schemaFieldDefinition = new SchemaFieldDefinition(schemaFieldDefinition); @@ -27,4 +26,7 @@ const schemaFieldUpdate = async function({ entity, fieldName, schemaFieldDefinit return respBody.data; }; -module.exports = schemaFieldUpdate; \ No newline at end of file +export default schemaFieldUpdate; +export { + schemaFieldUpdate, +}; diff --git a/src/client/schema-get.js b/src/client/schema-get.ts similarity index 72% rename from src/client/schema-get.js rename to src/client/schema-get.ts index c88bc0a..ccba8f5 100644 --- a/src/client/schema-get.js +++ b/src/client/schema-get.ts @@ -6,8 +6,7 @@ * @param {number} [options.projectId] - Project associated with entity. * @return {Object} Schema (fields) definition. */ -const schemaGet = async function({ entity, isFieldsWanted, projectId }) { - +const schemaGet = async function(this: any, { entity, isFieldsWanted, projectId }: { entity?: string; isFieldsWanted?: boolean; projectId?: number }): Promise { let path = '/schema'; if (entity) { path += `/${entity}`; @@ -16,7 +15,7 @@ const schemaGet = async function({ entity, isFieldsWanted, projectId }) { } } - let query = {}; + let query: Record = {}; if (projectId) query.project_id = projectId; @@ -28,4 +27,7 @@ const schemaGet = async function({ entity, isFieldsWanted, projectId }) { return respBody.data; }; -module.exports = schemaGet; +export default schemaGet; +export { + schemaGet, +}; From e61dcee99fe546a665c24f41ceb004257264a163 Mon Sep 17 00:00:00 2001 From: Max de Groot Date: Tue, 23 Dec 2025 16:24:37 +0100 Subject: [PATCH 11/18] chore(package): Bump version to 5.0.0 for major release --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0d29a95..d85596f 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "qs": "^6.10.5" }, "name": "shotgun-nodejs", - "version": "4.4.0", + "version": "5.0.0", "description": "Autodesk Shotgrid REST API library", "type": "module", "main": "./dist/index.js", From 8ecd16ea39f87d6bbc76898da8f9614617ba8c84 Mon Sep 17 00:00:00 2001 From: Max de Groot Date: Tue, 23 Dec 2025 16:28:30 +0100 Subject: [PATCH 12/18] docs(readme): Remove explicit grant type examples and update description in README --- README.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 1668742..a4b2b20 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,6 @@ const { ShotgunApiClient } = require('shotgun-nodejs'); let shotgun = new ShotgunApiClient({ siteUrl: 'https://mysite.shotgunstudio.com', credentials: { - grant_type: 'password', username: 'username', password: 'password', } @@ -41,7 +40,6 @@ a different type of credentials object to the constructor object as follows: ```javascript // Password-based { - grant_type: 'password', username: 'username', password: 'password', scope: 'sudo_as_login:username', // optional @@ -50,7 +48,6 @@ a different type of credentials object to the constructor object as follows: // Client-based { - grant_type: 'client_credentials', client_id: 'id', client_secret: 'secret', scope: 'sudo_as_login:username', // optional @@ -59,17 +56,17 @@ a different type of credentials object to the constructor object as follows: // Session token-based { - grant_type: 'session_token', session_token: 'token', } // Refresh token-based { - grant_type: 'refresh_token', refresh_token: 'token', } ``` +_Grant type will be automatically inferred based on the credentials object._ + ## Missing Support Currently not able to perform the following: @@ -89,7 +86,7 @@ Important files at a glance. ``` shotgun-nodejs └── src - └── client.js Main module + └── client.ts Main module ``` ## Contributing From 482279a548e0e25d1019a1a8c4f946d013a7b79d Mon Sep 17 00:00:00 2001 From: Max de Groot Date: Tue, 23 Dec 2025 16:30:27 +0100 Subject: [PATCH 13/18] refactor(client): Simplify response handling in async methods --- src/client/entity-delete.ts | 3 +-- src/client/schema-field-delete.ts | 3 +-- src/client/schema-field-revive.ts | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/client/entity-delete.ts b/src/client/entity-delete.ts index a39d2ce..31f171c 100644 --- a/src/client/entity-delete.ts +++ b/src/client/entity-delete.ts @@ -6,11 +6,10 @@ * @return {Object} Request result. */ const entityDelete = async function(this: any, { entity, entityId }: { entity: string; entityId: number }): Promise { - let respBody = await this.request({ + return await this.request({ method: 'DELETE', path: `/entity/${entity}/${entityId}`, }); - return respBody; }; export default entityDelete; diff --git a/src/client/schema-field-delete.ts b/src/client/schema-field-delete.ts index a2092ac..cf7eb63 100644 --- a/src/client/schema-field-delete.ts +++ b/src/client/schema-field-delete.ts @@ -6,11 +6,10 @@ * @return {Object} Operation response data. */ const schemaFieldDelete = async function(this: any, { entity, fieldName }: { entity: string; fieldName: string }): Promise { - let respBody = await this.request({ + return await this.request({ method: 'DELETE', path: `/schema/${entity}/fields/${fieldName}`, }); - return respBody; }; export default schemaFieldDelete; diff --git a/src/client/schema-field-revive.ts b/src/client/schema-field-revive.ts index 2a6dd8f..7c4fefa 100644 --- a/src/client/schema-field-revive.ts +++ b/src/client/schema-field-revive.ts @@ -6,11 +6,10 @@ * @return {Object} Operation response data. */ const schemaFieldRevive = async function(this: any, { entity, fieldName }: { entity: string; fieldName: string }): Promise { - let respBody = await this.request({ + return await this.request({ method: 'POST', path: `/schema/${entity}/fields/${fieldName}?revive=true`, }); - return respBody; }; export default schemaFieldRevive; From a47dfa76ac9c66df0160fe202e39f62ca670b9d0 Mon Sep 17 00:00:00 2001 From: Max de Groot Date: Tue, 23 Dec 2025 16:30:34 +0100 Subject: [PATCH 14/18] refactor(client): Remove unused `node-fetch` import in entity-item-upload.ts --- src/client/entity-item-upload.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/client/entity-item-upload.ts b/src/client/entity-item-upload.ts index c9e56bf..086ef18 100644 --- a/src/client/entity-item-upload.ts +++ b/src/client/entity-item-upload.ts @@ -1,5 +1,4 @@ -import fetch from 'node-fetch'; -import { fromBuffer } from 'file-type'; +import {fromBuffer} from 'file-type'; /** * Upload an entity item From 4b02b31d13cce69cf6e4bb381abe94200538a02a Mon Sep 17 00:00:00 2001 From: Max de Groot Date: Tue, 23 Dec 2025 16:44:22 +0100 Subject: [PATCH 15/18] chore(eslint): Configure TypeScript support in ESLint --- .eslintrc.json | 10 ++++++++-- package.json | 9 ++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 0da1226..60e8a15 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -5,14 +5,20 @@ "es6": true, "node": true }, - "extends": "eslint:recommended", + "plugins": ["@typescript-eslint"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended" + ], "globals": { "Atomics": "readonly", "SharedArrayBuffer": "readonly" }, + "parser": "@typescript-eslint/parser", "parserOptions": { "ecmaVersion": 2018, - "sourceType": "module" + "sourceType": "module", + "project": ["./tsconfig.json"] }, "rules": { "indent": [ diff --git a/package.json b/package.json index d85596f..15444f7 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,9 @@ "@types/node": "^25.0.3", "@types/node-fetch": "^2.6.13", "@types/qs": "^6.14.0", - "eslint": "^8.17.0", - "typescript": "^5.4.5" + "eslint": "^8.57.1", + "typescript": "^5.9.3", + "typescript-eslint": "^8.50.1" }, "exports": { ".": { @@ -25,7 +26,9 @@ "default": "./dist/index.js" } }, - "files": ["dist"], + "files": [ + "dist" + ], "scripts": { "build": "tsc -p tsconfig.json", "dev": "tsc -w -p tsconfig.json", From 083d51268701e7110f5f74dbd0e9ea3d912fe54a Mon Sep 17 00:00:00 2001 From: Max de Groot Date: Tue, 23 Dec 2025 16:44:31 +0100 Subject: [PATCH 16/18] chore(package): Update dependencies and regenerate `package-lock.json` for v5.0.0 --- package-lock.json | 905 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 772 insertions(+), 133 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1317330..e9982df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "shotgun-nodejs", - "version": "4.4.0", + "version": "5.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "shotgun-nodejs", - "version": "4.4.0", + "version": "5.0.0", "license": "ISC", "dependencies": { "async-retry": "^1.3.3", @@ -19,49 +19,149 @@ "@types/node": "^25.0.3", "@types/node-fetch": "^2.6.13", "@types/qs": "^6.14.0", - "eslint": "^8.17.0", - "typescript": "^5.4.5" + "eslint": "^8.57.1", + "typescript": "^5.9.3", + "typescript-eslint": "^8.50.1" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", - "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.3.2", - "globals": "^13.15.0", + "espree": "^9.6.0", + "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", - "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } }, "node_modules/@tokenizer/token": { "version": "0.3.0", @@ -113,11 +213,288 @@ "dev": true, "license": "MIT" }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.50.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.50.1.tgz", + "integrity": "sha512-PKhLGDq3JAg0Jk/aK890knnqduuI/Qj+udH7wCf0217IGi4gt+acgCyPVe79qoT+qKUvHMDQkwJeKW9fwl8Cyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.50.1", + "@typescript-eslint/type-utils": "8.50.1", + "@typescript-eslint/utils": "8.50.1", + "@typescript-eslint/visitor-keys": "8.50.1", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.50.1", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.50.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.50.1.tgz", + "integrity": "sha512-hM5faZwg7aVNa819m/5r7D0h0c9yC4DUlWAOvHAtISdFTc8xB86VmX5Xqabrama3wIPJ/q9RbGS1worb6JfnMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.50.1", + "@typescript-eslint/types": "8.50.1", + "@typescript-eslint/typescript-estree": "8.50.1", + "@typescript-eslint/visitor-keys": "8.50.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.50.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.50.1.tgz", + "integrity": "sha512-E1ur1MCVf+YiP89+o4Les/oBAVzmSbeRB0MQLfSlYtbWU17HPxZ6Bhs5iYmKZRALvEuBoXIZMOIRRc/P++Ortg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.50.1", + "@typescript-eslint/types": "^8.50.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.50.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.50.1.tgz", + "integrity": "sha512-mfRx06Myt3T4vuoHaKi8ZWNTPdzKPNBhiblze5N50//TSHOAQQevl/aolqA/BcqqbJ88GUnLqjjcBc8EWdBcVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.50.1", + "@typescript-eslint/visitor-keys": "8.50.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.50.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.50.1.tgz", + "integrity": "sha512-ooHmotT/lCWLXi55G4mvaUF60aJa012QzvLK0Y+Mp4WdSt17QhMhWOaBWeGTFVkb2gDgBe19Cxy1elPXylslDw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.50.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.50.1.tgz", + "integrity": "sha512-7J3bf022QZE42tYMO6SL+6lTPKFk/WphhRPe9Tw/el+cEwzLz1Jjz2PX3GtGQVxooLDKeMVmMt7fWpYRdG5Etg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.50.1", + "@typescript-eslint/typescript-estree": "8.50.1", + "@typescript-eslint/utils": "8.50.1", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.50.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.50.1.tgz", + "integrity": "sha512-v5lFIS2feTkNyMhd7AucE/9j/4V9v5iIbpVRncjk/K0sQ6Sb+Np9fgYS/63n6nwqahHQvbmujeBL7mp07Q9mlA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.50.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.50.1.tgz", + "integrity": "sha512-woHPdW+0gj53aM+cxchymJCrh0cyS7BTIdcDxWUNsclr9VDkOSbqC13juHzxOmQ22dDkMZEpZB+3X1WpUvzgVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.50.1", + "@typescript-eslint/tsconfig-utils": "8.50.1", + "@typescript-eslint/types": "8.50.1", + "@typescript-eslint/visitor-keys": "8.50.1", + "debug": "^4.3.4", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.50.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.50.1.tgz", + "integrity": "sha512-lCLp8H1T9T7gPbEuJSnHwnSuO9mDf8mfK/Nion5mZmiEaQD9sWf9W4dfeFqRyqRjF06/kBuTmAqcs9sewM2NbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.50.1", + "@typescript-eslint/types": "8.50.1", + "@typescript-eslint/typescript-estree": "8.50.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.50.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.50.1.tgz", + "integrity": "sha512-IrDKrw7pCRUR94zeuCSUWQ+w8JEf5ZX5jl/e6AHGSLi1/zIr0lgutfn/7JpfCey+urpgQEdrZVYzCaVVKiTwhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.50.1", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, "node_modules/acorn": { - "version": "8.7.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", - "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -130,6 +507,7 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -139,6 +517,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -178,7 +557,8 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" }, "node_modules/async-retry": { "version": "1.3.3", @@ -241,6 +621,7 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -334,7 +715,8 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/delayed-stream": { "version": "1.0.0", @@ -431,46 +813,51 @@ } }, "node_modules/eslint": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.17.0.tgz", - "integrity": "sha512-gq0m0BTJfci60Fz4nczYxNAlED+sMcihltndR8t9t1evnU/azx53x3t2UHXC/uRjcbvRw/XctpaNygSTcQD+Iw==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, + "license": "MIT", "dependencies": { - "@eslint/eslintrc": "^1.3.0", - "@humanwhocodes/config-array": "^0.9.2", - "ajv": "^6.10.0", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.2", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", "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.15.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" @@ -483,73 +870,59 @@ } }, "node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/espree": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", - "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.7.1", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -562,6 +935,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -574,6 +948,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -591,19 +966,50 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } }, "node_modules/file-entry-cache": { "version": "6.0.1", @@ -633,6 +1039,23 @@ "url": "https://github.com/sindresorhus/file-type?sponsor=1" } }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -684,12 +1107,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true - }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -760,10 +1177,11 @@ } }, "node_modules/globals": { - "version": "13.15.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", - "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -786,6 +1204,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -855,19 +1280,21 @@ ] }, "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -924,6 +1351,16 @@ "node": ">=0.10.0" } }, + "node_modules/is-path-inside": { + "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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -931,10 +1368,11 @@ "dev": true }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -946,7 +1384,8 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -959,6 +1398,7 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -967,6 +1407,22 @@ "node": ">= 0.8.0" } }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -1067,27 +1523,61 @@ } }, "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, + "license": "MIT", "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" } }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -1095,6 +1585,16 @@ "node": ">=6" } }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -1125,20 +1625,35 @@ "url": "https://github.com/sponsors/Borewit" } }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } }, "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -1158,6 +1673,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -1186,23 +1722,12 @@ "url": "https://github.com/sponsors/Borewit" } }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -1215,6 +1740,17 @@ "node": ">= 4" } }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -1230,6 +1766,30 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -1249,6 +1809,19 @@ } ] }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -1308,6 +1881,7 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -1349,6 +1923,23 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, "node_modules/token-types": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.0.tgz", @@ -1370,11 +1961,25 @@ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -1387,6 +1992,7 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -1408,6 +2014,30 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "8.50.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.50.1.tgz", + "integrity": "sha512-ytTHO+SoYSbhAH9CrYnMhiLx8To6PSSvqnvXyPUgPETCvB6eBKmTI9w6XMPS3HsBRGkwTVBX+urA8dYQx6bHfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.50.1", + "@typescript-eslint/parser": "8.50.1", + "@typescript-eslint/typescript-estree": "8.50.1", + "@typescript-eslint/utils": "8.50.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, "node_modules/undici-types": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", @@ -1420,6 +2050,7 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -1429,12 +2060,6 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -1465,10 +2090,11 @@ } }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -1478,6 +2104,19 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } From 47b3c7bbdad683ef9ae79d36c6688d1baa8e7a8e Mon Sep 17 00:00:00 2001 From: Max de Groot Date: Tue, 23 Dec 2025 16:48:55 +0100 Subject: [PATCH 17/18] refactor: Replace `let` with `const` across the codebase --- src/apply-mixins.ts | 6 ++-- src/client.ts | 50 +++++++++++++++---------------- src/client/entity-batch.ts | 4 +-- src/client/entity-create.ts | 2 +- src/client/entity-item-upload.ts | 12 ++++---- src/client/entity-read-all.ts | 6 ++-- src/client/entity-read.ts | 4 +-- src/client/entity-revive.ts | 2 +- src/client/entity-search.ts | 8 ++--- src/client/entity-update.ts | 2 +- src/client/preferences-get.ts | 4 +-- src/client/schema-field-create.ts | 4 +-- src/client/schema-field-update.ts | 4 +-- src/client/schema-get.ts | 4 +-- src/paginated-record-response.ts | 6 ++-- src/schema-field-definition.ts | 46 ++++++++++++++-------------- 16 files changed, 82 insertions(+), 82 deletions(-) diff --git a/src/apply-mixins.ts b/src/apply-mixins.ts index 72aec5b..b3c13a1 100644 --- a/src/apply-mixins.ts +++ b/src/apply-mixins.ts @@ -4,9 +4,9 @@ export function WithMixins< TBase extends Ctor, TMixins extends Record >(Base: TBase, mixins: TMixins) { - class Mixed extends Base {} - Object.assign(Mixed.prototype, mixins); - return Mixed as unknown as (new ( + class Mixed extends Base {} + Object.assign(Mixed.prototype, mixins); + return Mixed as unknown as (new ( ...args: ConstructorParameters ) => InstanceType & { [K in keyof TMixins]: TMixins[K]; diff --git a/src/client.ts b/src/client.ts index e34749a..cbdda00 100644 --- a/src/client.ts +++ b/src/client.ts @@ -5,7 +5,7 @@ import * as util from 'node:util'; import mixins from './client/index.js'; import {RequestError} from './error.js'; -import {WithMixins} from "./apply-mixins.js"; +import {WithMixins} from './apply-mixins.js'; const DEFAULT_API_BASE_PATH = '/api/v1.1'; const RETRY_COUNT = 2; @@ -69,16 +69,16 @@ class ShotgunApiClientBase { this.credentials = credentials; this._grant_type = GrantType.ClientCredentials; - if ("client_id" in credentials || "client_secret" in credentials) { + if ('client_id' in credentials || 'client_secret' in credentials) { this._grant_type = GrantType.ClientCredentials; } - else if ("username" in credentials || "password" in credentials) { + else if ('username' in credentials || 'password' in credentials) { this._grant_type = GrantType.PasswordCredentials; } - else if ("session_token" in credentials) { + else if ('session_token' in credentials) { this._grant_type = GrantType.SessionCredentials; } - else if ("refresh_token" in credentials) { + else if ('refresh_token' in credentials) { this._grant_type = GrantType.RefreshCredentials; } @@ -100,11 +100,11 @@ class ShotgunApiClientBase { } async connect(credentials: Credentials = this.credentials): Promise { - let { siteUrl, apiBasePath } = this; + const { siteUrl, apiBasePath } = this; - let url = new URL(`${siteUrl}${apiBasePath}/auth/access_token`); + const url = new URL(`${siteUrl}${apiBasePath}/auth/access_token`); - let resp = await this.fetchWithRetry(url, { + const resp = await this.fetchWithRetry(url, { method: 'POST', headers: { 'Accept': 'application/json', @@ -117,8 +117,8 @@ class ShotgunApiClientBase { }); if (!resp.ok) { - let respBody = await resp.text(); - let errorResp = new RequestError({ respBody }); + const respBody = await resp.text(); + const errorResp = new RequestError({ respBody }); throw new Error(`Error getting connect response: ${errorResp}`); } @@ -134,18 +134,18 @@ class ShotgunApiClientBase { } async refreshToken(): Promise { - let { siteUrl, apiBasePath, token } = this; + const { siteUrl, apiBasePath, token } = this; if (!token) return await this.connect(); - let url = new URL(`${siteUrl}${apiBasePath}/auth/access_token`); + const url = new URL(`${siteUrl}${apiBasePath}/auth/access_token`); url.search = qs.stringify({ refresh_token: token.refresh_token, grant_type: GrantType.RefreshCredentials, }); - let resp = await this.fetchWithRetry(url, { + const resp = await this.fetchWithRetry(url, { method: 'POST', headers: { 'Accept': 'application/json', @@ -155,8 +155,8 @@ class ShotgunApiClientBase { if (!resp.ok) { - let respBody = await resp.text(); - let errorResp = new RequestError({ respBody }); + const respBody = await resp.text(); + const errorResp = new RequestError({ respBody }); throw new Error(`Error getting refresh token response: ${errorResp}`); } @@ -175,7 +175,7 @@ class ShotgunApiClientBase { if (!token) return false; - let jwtPayload = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString()); + const jwtPayload = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString()); return (Date.now() / 1000) > jwtPayload.exp; } @@ -192,7 +192,7 @@ class ShotgunApiClientBase { } async requestRaw({ method = 'GET', path, headers, query, body, requestId, skipBasePathPrepend }: RequestParams): Promise { - let { siteUrl, apiBasePath, debug } = this; + const { siteUrl, apiBasePath, debug } = this; if (!path) path = '/'; @@ -206,14 +206,14 @@ class ShotgunApiClientBase { if (!headers) headers = {}; - let inHeaders = headers; + const inHeaders = headers; headers = Object.assign({ 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': await this.getAuthorizationHeader(), }, inHeaders); - let url = new URL(path, siteUrl); + const url = new URL(path, siteUrl); if (query) url.search = qs.stringify(query); @@ -227,11 +227,11 @@ class ShotgunApiClientBase { } async request(params: RequestParams): Promise { - let { debug } = this; - let { method, path } = params; + const { debug } = this; + const { method, path } = params; - let requestId = Math.random().toString(36).substr(2); - let resp = await this.requestRaw({ ...params, requestId }); + const requestId = Math.random().toString(36).substr(2); + const resp = await this.requestRaw({ ...params, requestId }); let respBody; try { @@ -250,7 +250,7 @@ class ShotgunApiClientBase { } async fetchWithRetry(...args: Parameters): Promise { - let { debug } = this; + const { debug } = this; const fetchFn = this.getFetch(); return retry( @@ -258,7 +258,7 @@ class ShotgunApiClientBase { if (debug) console.log(`Request attempt #${attemptNumber}`); - let resp = await fetchFn(...args); + const resp = await fetchFn(...args); if (attemptNumber <= RETRY_COUNT && (resp.status >= 500 || resp.status === 0)) { throw new Error('Force-trigger retry'); } diff --git a/src/client/entity-batch.ts b/src/client/entity-batch.ts index 4ea1f38..fd652e1 100644 --- a/src/client/entity-batch.ts +++ b/src/client/entity-batch.ts @@ -5,11 +5,11 @@ * @return {Object[]} Mapped request results. */ const entityBatch = async function(this: any, { requests }: { requests: unknown[] }): Promise { - let body = { + const body = { requests }; - let respBody = await this.request({ + const respBody = await this.request({ method: 'POST', path: '/entity/_batch/', body, diff --git a/src/client/entity-create.ts b/src/client/entity-create.ts index c3c00d6..a492d3c 100644 --- a/src/client/entity-create.ts +++ b/src/client/entity-create.ts @@ -6,7 +6,7 @@ * @return {Object} Created entity. */ const entityCreate = async function(this: any, { entity, data }: { entity: string; data: Record }): Promise { - let respBody = await this.request({ + const respBody = await this.request({ method: 'POST', path: `/entity/${entity}`, body: data diff --git a/src/client/entity-item-upload.ts b/src/client/entity-item-upload.ts index 086ef18..446b489 100644 --- a/src/client/entity-item-upload.ts +++ b/src/client/entity-item-upload.ts @@ -20,7 +20,7 @@ const entityItemUpload = async function(this: any, { entity, entityId, fieldName path += '/_upload'; // Get upload link - let uploadMetadata = await this.request({ + const uploadMetadata = await this.request({ method: 'GET', path, query: { filename: targetFileName }, @@ -35,8 +35,8 @@ const entityItemUpload = async function(this: any, { entity, entityId, fieldName // If upload link is not AWS, then API makes guess on the host. // Wrong in test and private environments. Apply correction if needed. - let uploadUrl = new URL(uploadMetadata.links.upload); - let siteUrl = new URL(this.siteUrl); + const uploadUrl = new URL(uploadMetadata.links.upload); + const siteUrl = new URL(this.siteUrl); if (uploadUrl.hostname === siteUrl.hostname) { uploadUrl.protocol = siteUrl.protocol; uploadUrl.port = siteUrl.port; @@ -53,17 +53,17 @@ const entityItemUpload = async function(this: any, { entity, entityId, fieldName const fetchFn = globalThis.fetch.bind(globalThis); // Upload file - let uploadResp = await fetchFn(uploadUrl, { + const uploadResp = await fetchFn(uploadUrl, { method: 'PUT', headers: { 'Content-Type': uploadFileBlob.type || 'application/octet-stream', - 'Content-Size': uploadFileBlob.size?.toString() ?? "" + 'Content-Size': uploadFileBlob.size?.toString() ?? '' }, body: uploadFileBlob as unknown as Blob, // Ignore type and size }); if (!uploadResp.ok) { - let reason = await uploadResp.text(); + const reason = await uploadResp.text(); throw new Error(`Error uploading file: ${reason}`); } diff --git a/src/client/entity-read-all.ts b/src/client/entity-read-all.ts index 88dda75..e3c3239 100644 --- a/src/client/entity-read-all.ts +++ b/src/client/entity-read-all.ts @@ -13,7 +13,7 @@ import { PaginatedRecordResponse } from '../paginated-record-response.js'; * @return {PaginatedRecordResponse} Targered partial response. */ const entityReadAll = async function(this: any, { entity, filter, fields, sort, pageSize, pageNumber, options }: { entity: string; filter?: Record; fields?: string[] | string; sort?: string[] | string; pageSize?: number; pageNumber?: number; options?: Record }): Promise { - let query: Record = { + const query: Record = { page: { size: pageSize || 500, number: pageNumber || 1, @@ -21,7 +21,7 @@ const entityReadAll = async function(this: any, { entity, filter, fields, sort, }; if (filter) { - for (let k in filter) { + for (const k in filter) { query[`filter[${k}]`] = filter[k]; } } @@ -40,7 +40,7 @@ const entityReadAll = async function(this: any, { entity, filter, fields, sort, query.options = options; } - let respBody = await this.request({ + const respBody = await this.request({ method: 'GET', path: `/entity/${entity}`, query, diff --git a/src/client/entity-read.ts b/src/client/entity-read.ts index 47b9103..7f837b2 100644 --- a/src/client/entity-read.ts +++ b/src/client/entity-read.ts @@ -8,7 +8,7 @@ * @return {Object} Entity information. */ const entityRead = async function(this: any, { entity, entityId, fields, options }: { entity: string; entityId: number; fields?: string[] | string; options?: Record }): Promise { - let query: Record = {}; + const query: Record = {}; if (Array.isArray(fields)) fields = fields.join(','); @@ -19,7 +19,7 @@ const entityRead = async function(this: any, { entity, entityId, fields, options query.options = options; } - let respBody = await this.request({ + const respBody = await this.request({ method: 'GET', path: `/entity/${entity}/${entityId}`, query, diff --git a/src/client/entity-revive.ts b/src/client/entity-revive.ts index a9b93eb..5e3d75a 100644 --- a/src/client/entity-revive.ts +++ b/src/client/entity-revive.ts @@ -6,7 +6,7 @@ * @return {Object} Revived entity. */ const entityRevive = async function(this: any, { entity, entityId }: { entity: string; entityId: number }): Promise { - let respBody = await this.request({ + const respBody = await this.request({ method: 'POST', path: `/entity/${entity}/${entityId}`, query: { diff --git a/src/client/entity-search.ts b/src/client/entity-search.ts index 6d9617d..7cf19b3 100644 --- a/src/client/entity-search.ts +++ b/src/client/entity-search.ts @@ -14,7 +14,7 @@ import { PaginatedRecordResponse } from '../paginated-record-response.js'; * @return {PaginatedRecordResponse} Query results. */ const entitySearch = async function(this: any, { entity, filters, fields, sort, pageSize, pageNumber }: { entity: string; filters: Record | unknown[]; fields?: string[] | string; sort?: string[] | string; pageSize?: number; pageNumber?: number }): Promise { - let query: Record = { + const query: Record = { page: { size: pageSize || 500, number: pageNumber || 1, @@ -31,11 +31,11 @@ const entitySearch = async function(this: any, { entity, filters, fields, sort, if (sort) query.sort = sort; - let contentType = Array.isArray(filters) ? 'array' : 'hash'; + const contentType = Array.isArray(filters) ? 'array' : 'hash'; - let body = { filters }; + const body = { filters }; - let respBody = await this.request({ + const respBody = await this.request({ method: 'POST', path: `/entity/${entity}/_search`, headers: { diff --git a/src/client/entity-update.ts b/src/client/entity-update.ts index 2ea4a26..bacd1db 100644 --- a/src/client/entity-update.ts +++ b/src/client/entity-update.ts @@ -7,7 +7,7 @@ * @return {Object} Updated entity. */ const entityUpdate = async function(this: any, { entity, entityId, data }: { entity: string; entityId: number; data: Record }): Promise { - let respBody = await this.request({ + const respBody = await this.request({ method: 'PUT', path: `/entity/${entity}/${entityId}`, body: data diff --git a/src/client/preferences-get.ts b/src/client/preferences-get.ts index 49b95de..311447b 100644 --- a/src/client/preferences-get.ts +++ b/src/client/preferences-get.ts @@ -8,11 +8,11 @@ const preferencesGet = async function(this: any, { names }: { names: string[] | if (!Array.isArray(names)) names = [names]; names = names.filter(Boolean).join(','); - let query = { + const query = { prefs: names }; - let respBody = await this.request({ + const respBody = await this.request({ method: 'GET', path: '/preferences', query, diff --git a/src/client/schema-field-create.ts b/src/client/schema-field-create.ts index e273901..d9138cc 100644 --- a/src/client/schema-field-create.ts +++ b/src/client/schema-field-create.ts @@ -11,9 +11,9 @@ const schemaFieldCreate = async function(this: any, { entity, schemaFieldDefinit if (!(schemaFieldDefinition instanceof SchemaFieldDefinition)) schemaFieldDefinition = new SchemaFieldDefinition(schemaFieldDefinition); - let body = schemaFieldDefinition.toBody(); + const body = schemaFieldDefinition.toBody(); - let respBody = await this.request({ + const respBody = await this.request({ method: 'POST', path: `/schema/${entity}/fields`, body, diff --git a/src/client/schema-field-update.ts b/src/client/schema-field-update.ts index 769a741..2b2066a 100644 --- a/src/client/schema-field-update.ts +++ b/src/client/schema-field-update.ts @@ -13,12 +13,12 @@ const schemaFieldUpdate = async function(this: any, { entity, fieldName, schemaF if (!(schemaFieldDefinition instanceof SchemaFieldDefinition)) schemaFieldDefinition = new SchemaFieldDefinition(schemaFieldDefinition); - let body = schemaFieldDefinition.toBody(); + const body = schemaFieldDefinition.toBody(); if (projectId) body.project_id = projectId; - let respBody = await this.request({ + const respBody = await this.request({ method: 'PUT', path: `/schema/${entity}/fields/${fieldName}`, body, diff --git a/src/client/schema-get.ts b/src/client/schema-get.ts index ccba8f5..b210780 100644 --- a/src/client/schema-get.ts +++ b/src/client/schema-get.ts @@ -15,11 +15,11 @@ const schemaGet = async function(this: any, { entity, isFieldsWanted, projectId } } - let query: Record = {}; + const query: Record = {}; if (projectId) query.project_id = projectId; - let respBody = await this.request({ + const respBody = await this.request({ method: 'GET', path, query, diff --git a/src/paginated-record-response.ts b/src/paginated-record-response.ts index 1b53808..5abcd3a 100644 --- a/src/paginated-record-response.ts +++ b/src/paginated-record-response.ts @@ -30,12 +30,12 @@ class PaginatedRecordResponse { } async getNext({ client }: { client: RequestClient }): Promise | undefined> { - let path = this.links.next; + const path = this.links.next; return this._get({ path, client }); } async getPrev({ client }: { client: RequestClient }): Promise | undefined> { - let path = this.links.prev; + const path = this.links.prev; return this._get({ path, client }); } @@ -43,7 +43,7 @@ class PaginatedRecordResponse { if (!path) return; - let out = new PaginatedRecordResponse(await client.request({ + const out = new PaginatedRecordResponse(await client.request({ path, skipBasePathPrepend: true }) as PaginatedRecordParams); diff --git a/src/schema-field-definition.ts b/src/schema-field-definition.ts index 219e09b..4741e92 100644 --- a/src/schema-field-definition.ts +++ b/src/schema-field-definition.ts @@ -10,24 +10,24 @@ type SchemaFieldDefinitionBody = { class SchemaFieldDefinition { static DATA_TYPES = [ - 'calculated', - 'checkbox', - 'currency', - 'date', - 'date_time', - 'duration', - 'entity', - 'float', - 'footage', - 'list', - 'multi_entity', - 'number', - 'percent', - 'status_list', - 'text', - 'timecode', - 'url', - 'uuid', + 'calculated', + 'checkbox', + 'currency', + 'date', + 'date_time', + 'duration', + 'entity', + 'float', + 'footage', + 'list', + 'multi_entity', + 'number', + 'percent', + 'status_list', + 'text', + 'timecode', + 'url', + 'uuid', ]; dataType?: string; @@ -39,7 +39,7 @@ class SchemaFieldDefinition { if (!body) return; - let { data_type, properties } = body; + const { data_type, properties } = body; this.setDataType(data_type); this.setProperties(properties); @@ -53,7 +53,7 @@ class SchemaFieldDefinition { setProperties(properties: SchemaProperty[] | Record): void { if (Array.isArray(properties)) { - for (let p of properties) { + for (const p of properties) { this.properties[p.property_name] = p.value; } return; @@ -68,9 +68,9 @@ class SchemaFieldDefinition { } toBody(): { data_type: string | undefined; properties: SchemaProperty[], project_id?: number } { - let data_type = this.dataType; - let properties: SchemaProperty[] = []; - for (let k in this.properties) { + const data_type = this.dataType; + const properties: SchemaProperty[] = []; + for (const k in this.properties) { properties.push({ property_name: k, value: this.properties[k], From b132f981ed88a396023fd3216c302bc8c04f6b07 Mon Sep 17 00:00:00 2001 From: Max de Groot Date: Tue, 23 Dec 2025 17:17:02 +0100 Subject: [PATCH 18/18] docs(readme): Update import syntax in library usage example --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a4b2b20..973f144 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ A companion CLI can be found at https://github.com/shotgunsoftware/shotgrid-node ### Using as a library ```javascript -const { ShotgunApiClient } = require('shotgun-nodejs'); +import ShotgunApiClient from 'shotgun-nodejs'; (async function() { let shotgun = new ShotgunApiClient({