From dd5ee3579c43f4303ce65a11820611c1022c157d Mon Sep 17 00:00:00 2001 From: skyflow-himanshu Date: Tue, 23 Dec 2025 17:15:19 +0530 Subject: [PATCH 1/4] SK-2455: add linter to node sdk v2 --- eslint.config.mjs | 32 + package-lock.json | 945 +++++++++++++++++- package.json | 8 +- samples/vault-api/data-residency.ts | 1 + src/utils/jwt-utils/index.ts | 1 + .../deidentify-file/bleep-audio/index.ts | 1 + test/vault/utils/jwt-utils/jwt.test.js | 1 + test/vault/utils/utils.test.js | 1 + 8 files changed, 979 insertions(+), 11 deletions(-) create mode 100644 eslint.config.mjs diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 00000000..3ba9b9f3 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,32 @@ +import tseslint from "typescript-eslint"; + +export default [ + { + files: ["**/*.{js,mjs,cjs,ts}"], + + languageOptions: { + parser: tseslint.parser, + parserOptions: { sourceType: "module" } + }, + + linterOptions: { + reportUnusedDisableDirectives: "off" + }, + + plugins: { + "@typescript-eslint": tseslint.plugin, + }, + + rules: { + "camelcase": ["error", { "properties": "never", "ignoreImports": true }] + } + }, + { + ignores: [ + "node_modules/", + "dist/", + "coverage/", + "src/_generated_/", + ] + } +]; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 104f270a..319d076a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "@babel/plugin-transform-runtime": "^7.25.7", "@babel/preset-env": "^7.25.8", "@babel/preset-typescript": "^7.25.7", + "@eslint/js": "^9.39.2", "@types/jest": "^29.5.14", "@types/jsonwebtoken": "^9.0.6", "@types/node": "^18.19.70", @@ -36,12 +37,15 @@ "@types/readable-stream": "^4.0.18", "@types/url-join": "4.0.1", "cspell": "^9.3.1", + "eslint": "^9.39.2", + "globals": "^16.5.0", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", "prettier": "3.6.2", "ts-jest": "^29.1.1", "ts-loader": "^9.5.1", "typescript": "~5.7.2", + "typescript-eslint": "^8.50.0", "webpack": "^5.97.1" } }, @@ -955,6 +959,15 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-classes/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/plugin-transform-computed-properties": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", @@ -1872,6 +1885,15 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/types": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz", @@ -2481,6 +2503,240 @@ "node": ">=20" } }, + "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, + "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/eslint-utils/node_modules/eslint-visitor-keys": { + "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, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "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, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "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 + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "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 + }, + "node_modules/@eslint/js": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.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, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -3137,6 +3393,261 @@ "dev": true, "license": "MIT" }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.50.0.tgz", + "integrity": "sha512-O7QnmOXYKVtPrfYzMolrCTfkezCJS9+ljLdKW/+DCvRsc3UAz+sbH6Xcsv7p30+0OwUbeWfUDAQE0vpabZ3QLg==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.50.0", + "@typescript-eslint/type-utils": "8.50.0", + "@typescript-eslint/utils": "8.50.0", + "@typescript-eslint/visitor-keys": "8.50.0", + "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.0", + "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, + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.50.0.tgz", + "integrity": "sha512-6/cmF2piao+f6wSxUsJLZjck7OQsYyRtcOZS02k7XINSNlz93v6emM8WutDQSXnroG2xwYlEVHJI+cPA7CPM3Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "8.50.0", + "@typescript-eslint/types": "8.50.0", + "@typescript-eslint/typescript-estree": "8.50.0", + "@typescript-eslint/visitor-keys": "8.50.0", + "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.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.50.0.tgz", + "integrity": "sha512-Cg/nQcL1BcoTijEWyx4mkVC56r8dj44bFDvBdygifuS20f3OZCHmFbjF34DPSi07kwlFvqfv/xOLnJ5DquxSGQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.50.0", + "@typescript-eslint/types": "^8.50.0", + "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.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.50.0.tgz", + "integrity": "sha512-xCwfuCZjhIqy7+HKxBLrDVT5q/iq7XBVBXLn57RTIIpelLtEIZHXAF/Upa3+gaCpeV1NNS5Z9A+ID6jn50VD4A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.50.0", + "@typescript-eslint/visitor-keys": "8.50.0" + }, + "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.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.50.0.tgz", + "integrity": "sha512-vxd3G/ybKTSlm31MOA96gqvrRGv9RJ7LGtZCn2Vrc5htA0zCDvcMqUkifcjrWNNKXHUU3WCkYOzzVSFBd0wa2w==", + "dev": true, + "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.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.50.0.tgz", + "integrity": "sha512-7OciHT2lKCewR0mFoBrvZJ4AXTMe/sYOe87289WAViOocEmDjjv8MvIOT2XESuKj9jp8u3SZYUSh89QA4S1kQw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.50.0", + "@typescript-eslint/typescript-estree": "8.50.0", + "@typescript-eslint/utils": "8.50.0", + "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.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.50.0.tgz", + "integrity": "sha512-iX1mgmGrXdANhhITbpp2QQM2fGehBse9LbTf0sidWK6yg/NE+uhV5dfU1g6EYPlcReYmkE9QLPq/2irKAmtS9w==", + "dev": true, + "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.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.50.0.tgz", + "integrity": "sha512-W7SVAGBR/IX7zm1t70Yujpbk+zdPq/u4soeFSknWFdXIFuWsBGBOUu/Tn/I6KHSKvSh91OiMuaSnYp3mtPt5IQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/project-service": "8.50.0", + "@typescript-eslint/tsconfig-utils": "8.50.0", + "@typescript-eslint/types": "8.50.0", + "@typescript-eslint/visitor-keys": "8.50.0", + "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, + "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, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/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, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.50.0.tgz", + "integrity": "sha512-87KgUXET09CRjGCi2Ejxy3PULXna63/bMYv72tCAlDJC3Yqwln0HiFJ3VJMst2+mEtNtZu5oFvX4qJGjKsnAgg==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.50.0", + "@typescript-eslint/types": "8.50.0", + "@typescript-eslint/typescript-estree": "8.50.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/visitor-keys": { + "version": "8.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.50.0.tgz", + "integrity": "sha512-Xzmnb58+Db78gT/CCj/PVCvK+zxbnsw6F+O1oheYszJbBSdEjVhQi3C/Xttzxgi/GLmpvOggRs1RFpiJ8+c34Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.50.0", + "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/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", @@ -3333,11 +3844,10 @@ } }, "node_modules/acorn": { - "version": "8.14.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", - "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "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" }, @@ -3356,6 +3866,15 @@ "acorn-walk": "^8.0.2" } }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/acorn-walk": { "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", @@ -4464,6 +4983,12 @@ } } }, + "node_modules/deep-is": { + "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 + }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -4738,6 +5263,65 @@ "source-map": "~0.6.1" } }, + "node_modules/eslint": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.2", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -4762,6 +5346,131 @@ "node": ">=4.0" } }, + "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, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/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, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "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 + }, + "node_modules/eslint/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, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/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, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -4776,6 +5485,18 @@ "node": ">=4" } }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -4901,6 +5622,12 @@ "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 + }, "node_modules/fast-uri": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", @@ -4928,6 +5655,18 @@ "bser": "2.1.1" } }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/filelist": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", @@ -4988,6 +5727,19 @@ "node": ">=8" } }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/flatted": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", @@ -5172,6 +5924,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/glob-to-regexp": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", @@ -5196,13 +5960,15 @@ } }, "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", + "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", "dev": true, - "license": "MIT", "engines": { - "node": ">=4" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/gopd": { @@ -5365,6 +6131,15 @@ ], "license": "BSD-3-Clause" }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", @@ -5498,6 +6273,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -5518,6 +6302,18 @@ "node": ">=6" } }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -6368,6 +7164,12 @@ "node": ">=6" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -6382,6 +7184,12 @@ "dev": true, "license": "MIT" }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -6453,6 +7261,15 @@ "integrity": "sha512-86GgN2vzfUu7m9Wcj63iUkuDzFNYFVmjeDm2GzWpUk+opB0pEpMsw6ePCMrhYkumz2C1ihqtZzOMAg7FiXcNoQ==", "license": "MIT" }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -6473,6 +7290,19 @@ "node": ">=6" } }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -6553,6 +7383,12 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "node_modules/lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", @@ -6833,6 +7669,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "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.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", @@ -7013,6 +7866,15 @@ "node": ">=8" } }, + "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, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/prettier": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", @@ -7920,6 +8782,18 @@ "node": ">=12" } }, + "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, + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, "node_modules/ts-jest": { "version": "29.3.2", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.3.2.tgz", @@ -8040,6 +8914,18 @@ "node": ">= 8" } }, + "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, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -8077,6 +8963,29 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "8.50.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.50.0.tgz", + "integrity": "sha512-Q1/6yNUmCpH94fbgMUMg2/BSAr/6U7GBk61kZTv1/asghQOWOjTlp9K8mixS5NcJmm2creY+UFfGeW/+OcA64A==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.50.0", + "@typescript-eslint/parser": "8.50.0", + "@typescript-eslint/typescript-estree": "8.50.0", + "@typescript-eslint/utils": "8.50.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/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", @@ -8169,6 +9078,15 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/url-join": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", @@ -8373,6 +9291,15 @@ "node": ">= 8" } }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", diff --git a/package.json b/package.json index ba2b35e2..bf2a4658 100644 --- a/package.json +++ b/package.json @@ -7,9 +7,9 @@ "scripts": { "test": "jest --coverage", "build": "tsc", - "eslint": "eslint '**/*.js' --max-warnings 0", + "eslint": "eslint '**/*.{js,ts}' --max-warnings 0", "prettier": "prettier --list-different '**/*.{js,ts}'", - "lint": "npm run prettier && npm run eslint", + "lint": "npm run eslint", "lint-fix": "prettier --write '**/*.{js,ts}' && eslint --fix '**/*.js'", "spellcheck": "cspell '**/*.{ts,js,md}'", "docs-gen": "typedoc && node scripts/docs-script/markdown-gen.js && npx ts-node scripts/docs-script/processMarkdown.ts" @@ -52,6 +52,7 @@ "@babel/plugin-transform-runtime": "^7.25.7", "@babel/preset-env": "^7.25.8", "@babel/preset-typescript": "^7.25.7", + "@eslint/js": "^9.39.2", "@types/jest": "^29.5.14", "@types/jsonwebtoken": "^9.0.6", "@types/node": "^18.19.70", @@ -60,12 +61,15 @@ "@types/readable-stream": "^4.0.18", "@types/url-join": "4.0.1", "cspell": "^9.3.1", + "eslint": "^9.39.2", + "globals": "^16.5.0", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", "prettier": "3.6.2", "ts-jest": "^29.1.1", "ts-loader": "^9.5.1", "typescript": "~5.7.2", + "typescript-eslint": "^8.50.0", "webpack": "^5.97.1" } } diff --git a/samples/vault-api/data-residency.ts b/samples/vault-api/data-residency.ts index d70ded1c..395a45bd 100644 --- a/samples/vault-api/data-residency.ts +++ b/samples/vault-api/data-residency.ts @@ -78,6 +78,7 @@ async function transferDataBetweenVaults() { // Remove skyflow_id from the data (if needed for re-insertion) const sanitizedData = insertData.map((item: Record) => { + // eslint-disable-next-line camelcase const { skyflow_id, ...rest } = item; // Exclude the skyflow_id field return rest; }); diff --git a/src/utils/jwt-utils/index.ts b/src/utils/jwt-utils/index.ts index 489f812c..8a55a2e4 100644 --- a/src/utils/jwt-utils/index.ts +++ b/src/utils/jwt-utils/index.ts @@ -1,3 +1,4 @@ +// eslint-disable-next-line camelcase import jwt_decode, { JwtPayload } from 'jwt-decode'; import { MessageType, printLog } from '..'; import logs from '../logs'; diff --git a/src/vault/model/options/deidentify-file/bleep-audio/index.ts b/src/vault/model/options/deidentify-file/bleep-audio/index.ts index 630dd8af..d494e631 100644 --- a/src/vault/model/options/deidentify-file/bleep-audio/index.ts +++ b/src/vault/model/options/deidentify-file/bleep-audio/index.ts @@ -1,3 +1,4 @@ +/* eslint-disable camelcase */ export class Bleep { private _gain?: number; private _frequency?: number; diff --git a/test/vault/utils/jwt-utils/jwt.test.js b/test/vault/utils/jwt-utils/jwt.test.js index 14c397b8..404188f7 100644 --- a/test/vault/utils/jwt-utils/jwt.test.js +++ b/test/vault/utils/jwt-utils/jwt.test.js @@ -1,3 +1,4 @@ +/* eslint-disable camelcase */ import jwt_decode from 'jwt-decode'; import { isTokenValid, isExpired } from '../../../../src/utils/jwt-utils'; diff --git a/test/vault/utils/utils.test.js b/test/vault/utils/utils.test.js index ffea9c3d..817cb05e 100644 --- a/test/vault/utils/utils.test.js +++ b/test/vault/utils/utils.test.js @@ -1,3 +1,4 @@ +/* eslint-disable camelcase */ import errorMessages from "../../../src/error/messages"; import { Env, getConnectionBaseURL, getVaultURL, validateToken, isValidURL, fillUrlWithPathAndQueryParams, generateSDKMetrics, printLog, getToken, getBearerToken, MessageType, LogLevel } from "../../../src/utils"; import jwt_decode from 'jwt-decode'; From 9d7d6ec3584925f0a7bc859ed747a00f3198f2c2 Mon Sep 17 00:00:00 2001 From: Aadarsh Date: Fri, 23 Jan 2026 14:02:55 +0530 Subject: [PATCH 2/4] aadarsh-st/SK-2495 Replace Hardcore values with constants --- eslint.config.mjs | 43 +++- package-lock.json | 19 +- src/service-account/index.ts | 34 +-- src/utils/index.ts | 120 +++++++++-- src/utils/validations/index.ts | 20 +- src/vault/client/index.ts | 24 +-- src/vault/controller/connections/index.ts | 14 +- src/vault/controller/detect/index.ts | 49 +++-- src/vault/controller/vault/index.ts | 14 +- src/vault/skyflow/index.ts | 48 ++--- test/vault/controller/connection.test.js | 8 +- test/vault/controller/detect.test.js | 243 +++++++++++++--------- test/vault/controller/vault.test.js | 18 +- 13 files changed, 402 insertions(+), 252 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 3ba9b9f3..263c2112 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,32 +1,53 @@ -import tseslint from "typescript-eslint"; +import tseslint from 'typescript-eslint'; +export default tseslint.config( -export default [ { files: ["**/*.{js,mjs,cjs,ts}"], languageOptions: { parser: tseslint.parser, - parserOptions: { sourceType: "module" } + parserOptions: { + projectSouce: true, + tsconfigRootDir: import.meta.dirname, + sourceType: "module", + }, }, - linterOptions: { + linterOptions: { reportUnusedDisableDirectives: "off" }, - plugins: { "@typescript-eslint": tseslint.plugin, }, - rules: { - "camelcase": ["error", { "properties": "never", "ignoreImports": true }] - } - }, + "camelcase": ["error", { "properties": "never", "ignoreImports": true }], + "dot-notation": "off", + "no-restricted-syntax": [ + "error", + { + // Bans obj['key'] in favor of obj.key + selector: "MemberExpression[computed=true] > Literal[value=/./]", + message: "Do not use string literals for object access. Use dot notation (obj.prop) or constants.", + }, + { + // Bans comparison against magic strings, excluding type names + selector: "BinaryExpression[operator=/^(==|===|!=|!==)$/] > Literal[value=/^(?!(string|number|boolean|object|undefined|{})$).+/]", + message: "Do not compare against magic strings. Use constants instead." + } + ], + }, + + } + , { ignores: [ "node_modules/", "dist/", "coverage/", - "src/_generated_/", + "src/ _generated_/", + "test/**", + "samples/**", + "scripts/**", ] } -]; \ No newline at end of file +); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 319d076a..520b77c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "skyflow-node", - "version": "2.0.2", + "version": "2.0.2-dev.2a81ccd", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "skyflow-node", - "version": "2.0.2", + "version": "2.0.2-dev.2a81ccd", "license": "MIT", "dependencies": { "@babel/runtime": "^7.27.1", @@ -5788,21 +5788,6 @@ "dev": true, "license": "ISC" }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", diff --git a/src/service-account/index.ts b/src/service-account/index.ts index c8217905..9a4d32ea 100644 --- a/src/service-account/index.ts +++ b/src/service-account/index.ts @@ -1,7 +1,7 @@ import * as fs from 'fs'; import jwt from "jsonwebtoken"; import { V1GetAuthTokenRequest, V1GetAuthTokenResponse } from '../ _generated_/rest/api'; -import { getBaseUrl, LogLevel, MessageType, parameterizedString, printLog } from '../utils'; +import { getBaseUrl, LogLevel, MessageType, parameterizedString, printLog, HTTP_HEADER, CONTENT_TYPE, HTTP_STATUS_CODE, JWT, ENCODING_TYPE } from '../utils'; import Client from './client'; import logs from '../utils/logs'; import SkyflowError from '../error'; @@ -44,7 +44,7 @@ function generateBearerToken(credentialsFilePath: string, options?: BearerTokenO printLog(parameterizedString(logs.errorLogs.FILE_NOT_FOUND, [credentialsFilePath]), MessageType.ERROR, options?.logLevel); reject(new SkyflowError(SKYFLOW_ERROR_CODE.FILE_NOT_FOUND, [credentialsFilePath])); } - credentials = fs.readFileSync(credentialsFilePath, "utf8"); + credentials = fs.readFileSync(credentialsFilePath, ENCODING_TYPE.UTF8); if (credentials === '') { printLog(logs.errorLogs.EMPTY_FILE, MessageType.ERROR, options?.logLevel); @@ -124,8 +124,8 @@ function getToken(credentials, options?: BearerTokenOptions): Promise) => { successResponse(res.data, options?.logLevel).then((response) => resolve(response)).catch(err => reject(err)) }) @@ -168,7 +168,7 @@ function generateSignedDataTokens(credentialsFilePath: string, options: SignedDa printLog(parameterizedString(logs.errorLogs.FILE_NOT_FOUND, [credentialsFilePath]), MessageType.ERROR, options?.logLevel); reject(new SkyflowError(SKYFLOW_ERROR_CODE.FILE_NOT_FOUND, [credentialsFilePath])); } - credentials = fs.readFileSync(credentialsFilePath, "utf8"); + credentials = fs.readFileSync(credentialsFilePath, ENCODING_TYPE.UTF8); if (credentials === '') { printLog(logs.errorLogs.EMPTY_FILE, MessageType.ERROR, options?.logLevel); @@ -237,13 +237,13 @@ function getSignedTokens(credentials, options: SignedDataTokensOptions): Promise } else { expiryTime = Math.floor(Date.now() / 1000) + 60; } - const prefix = "signed_token_"; + const prefix = JWT.SIGNED_TOKEN_PREFIX; let responseArray: SignedDataTokensResponse[] = []; if (options && options?.dataTokens) { options.dataTokens.forEach((token) => { const claims = { - iss: "sdk", + iss: JWT.ISSUER_SDK, key: credentialsObj.keyID, aud: credentialsObj.tokenURI, exp: expiryTime, @@ -265,8 +265,8 @@ function getSignedTokens(credentials, options: SignedDataTokensOptions): Promise reject(new SkyflowError(SKYFLOW_ERROR_CODE.MISSING_PRIVATE_KEY)); } else { - const privateKey = credentialsObj.privateKey.toString("utf8"); - const signedJwt = jwt.sign(claims, privateKey, { algorithm: "RS256" }); + const privateKey = credentialsObj.privateKey.toString(ENCODING_TYPE.UTF8); + const signedJwt = jwt.sign(claims, privateKey, { algorithm: JWT.ALGORITHM_RS256 }); const responseObject = getSignedDataTokenResponseObject(prefix + signedJwt, token); responseArray.push(responseObject) } @@ -287,9 +287,9 @@ function generateSignedDataTokensFromCreds(credentials, options: SignedDataToken function failureResponse(err: ServiceAccountResponseError, options?: BearerTokenOptions) { return new Promise((_, reject) => { if (err.rawResponse) { - const requestId = err?.rawResponse?.headers?.get('x-request-id'); - const contentType = err?.rawResponse?.headers?.get('content-type'); - if (contentType && contentType.includes('application/json')) { + const requestId = err?.rawResponse?.headers?.get(HTTP_HEADER.X_REQUEST_ID); + const contentType = err?.rawResponse?.headers?.get(HTTP_HEADER.CONTENT_TYPE_LOWER); + if (contentType && contentType.includes(CONTENT_TYPE.APPLICATION_JSON)) { let description = err?.body?.error?.message ?? err?.body; printLog(description, MessageType.ERROR, options?.logLevel); reject(new SkyflowError({ @@ -297,7 +297,7 @@ function failureResponse(err: ServiceAccountResponseError, options?: BearerToken message: description, request_ID: requestId, })); - } else if (contentType && contentType.includes('text/plain')) { + } else if (contentType && contentType.includes(CONTENT_TYPE.TEXT_PLAIN)) { let description = err?.body; printLog(description, MessageType.ERROR, options?.logLevel); reject(new SkyflowError({ @@ -317,7 +317,7 @@ function failureResponse(err: ServiceAccountResponseError, options?: BearerToken } else { printLog(err.message, MessageType.ERROR, options?.logLevel); reject(new SkyflowError({ - http_code: "500", + http_code: String(HTTP_STATUS_CODE.INTERNAL_SERVER_ERROR), message: err.message, })) } @@ -352,7 +352,7 @@ function signedDataTokenSuccessResponse(res: SignedDataTokensResponse[], logLeve export function getRolesForScopedToken(roleIDs: string[]) { let str = '' roleIDs?.forEach((role) => { - str = str + "role:" + role + " " + str = str + JWT.ROLE_PREFIX + role + " " }) return str; } diff --git a/src/utils/index.ts b/src/utils/index.ts index 856359e3..61b6b5a9 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -13,27 +13,29 @@ import { StringKeyValueMapType } from "../vault/types"; dotenv.config(); -export const SDK_METRICS_HEADER_KEY = "sky-metadata"; +export const SDK = { + METRICS_HEADER_KEY: "sky-metadata", +} as const; -export const SKYFLOW_ID = "skyflowId"; +export const SKYFLOW = { + ID: "skyflowId", + AUTH_HEADER_KEY: "x-skyflow-authorization", +}; export const BAD_REQUEST = "Bad Request"; -export const SKYFLOW_AUTH_HEADER_KEY = "x-skyflow-authorization"; - -export const REQUEST_ID_KEY = "x-request-id"; - -export const LOGLEVEL = "loglevel"; - -export const CREDENTIALS = "credentials"; - -export const VAULT_ID = "vaultId"; - -export const CONNECTION_ID = "connectionId"; - -export const VAULT = "vault"; +export const REQUEST = { + ID_KEY: "x-request-id", +}; -export const CONNECTION = "connection"; +export const CONFIG = { + LOGLEVEL: "loglevel", + CREDENTIALS: "credentials", + VAULT_ID: "vaultId", + CONNECTION_ID: "connectionId", + VAULT: "vault", + CONNECTION: "connection", +} as const; export enum TokenMode { DISABLE = 'DISABLE', @@ -123,6 +125,7 @@ export const CONTROLLER_TYPES = { CONNECTION: 'CONNECTION', } + export enum DetectOutputTranscription { DIARIZED_TRANSCRIPTION = "diarized_transcription", MEDICAL_DIARIZED_TRANSCRIPTION = "medical_diarized_transcription", @@ -214,6 +217,89 @@ export enum TokenType { VAULT_TOKEN = 'vault_token' } + +// HTTP Status Codes +export const HTTP_STATUS_CODE = { + OK: 200, + BAD_REQUEST: 400, + INTERNAL_SERVER_ERROR: 500, +} as const; + +// Content Types +export const CONTENT_TYPE = { + APPLICATION_JSON: 'application/json', + APPLICATION_X_WWW_FORM_URLENCODED: 'application/x-www-form-urlencoded', + TEXT_PLAIN: 'text/plain', +} as const; + +// HTTP Headers +export const HTTP_HEADER = { + CONTENT_TYPE: 'Content-Type', + CONTENT_TYPE_LOWER: 'content-type', + X_REQUEST_ID: 'x-request-id', + ERROR_FROM_CLIENT: 'error-from-client', +} as const; + +// Detect API Status Values +export const DETECT_STATUS = { + IN_PROGRESS: 'IN_PROGRESS', + SUCCESS: 'SUCCESS', + FAILED: 'FAILED', +} as const; + +// File Extensions +export const FILE_EXTENSION = { + JSON: 'json', + MP3: 'mp3', + WAV: 'wav', +} as const; + +// File Format Types +export const FILE_FORMAT_TYPE = { + TXT: 'txt', + PDF: 'pdf', +} as const; + +// File Processing +export const FILE_PROCESSING = { + PROCESSED_PREFIX: 'processed-', + DEIDENTIFIED_PREFIX: 'deidentified.', + ENTITIES: 'entities', +} as const; + +// Encoding Types +export const ENCODING_TYPE = { + UTF8: 'utf8', + BASE64: 'base64', + BINARY: 'binary', + UTF_8: 'utf-8', +} as const; + +// JWT Constants +export const JWT = { + ALGORITHM_RS256: 'RS256', + GRANT_TYPE_JWT_BEARER: 'urn:ietf:params:oauth:grant-type:jwt-bearer', + ISSUER_SDK: 'sdk', + SIGNED_TOKEN_PREFIX: 'signed_token_', + ROLE_PREFIX: 'role:', +} as const; + +// API Key Prefix +export const API_KEY = { + PREFIX: 'sky-', +}as const ; + +// URL Protocol +export const URL_PROTOCOL = { + HTTPS: 'https', +} as const; + +// Boolean String Values +export const BOOLEAN_STRING = { + TRUE: 'true', +} as const; + + export interface ISkyflowError { http_status?: string | number | null, grpc_code?: string | number | null, @@ -486,7 +572,7 @@ export const generateSDKMetrics = (logLevel?: LogLevel) => { }; export const isValidURL = (url: string) => { - if (url && url.substring(0, 5).toLowerCase() !== 'https') { + if (url && url.substring(0, 5).toLowerCase() !== URL_PROTOCOL.HTTPS) { return false; } try { diff --git a/src/utils/validations/index.ts b/src/utils/validations/index.ts index f688040e..5e72f408 100644 --- a/src/utils/validations/index.ts +++ b/src/utils/validations/index.ts @@ -1,4 +1,4 @@ -import { CONNECTION, CONNECTION_ID, Env, isValidURL, LogLevel, MessageType, RequestMethod, OrderByEnum, parameterizedString, printLog, RedactionType, SKYFLOW_ID, VAULT, VAULT_ID, TokenMode } from ".."; +import { CONFIG, Env, isValidURL, LogLevel, MessageType, RequestMethod, OrderByEnum, parameterizedString, printLog, RedactionType, SKYFLOW, TokenMode, API_KEY } from ".."; import { V1Byot } from "../../ _generated_/rest/api"; import SkyflowError from "../../error"; import SKYFLOW_ERROR_CODE from "../../error/codes"; @@ -64,7 +64,7 @@ export function isValidAPIKey(apiKey: string) { if (!apiKey || apiKey === null || apiKey === undefined) { return false; } - if (apiKey && typeof apiKey === 'string' && apiKey.startsWith("sky-")) { + if (apiKey && typeof apiKey === 'string' && apiKey.startsWith(API_KEY.PREFIX)) { return true; } return false; @@ -116,11 +116,11 @@ export const validateSkyflowConfig = (config: SkyflowConfig, logLevel: LogLevel } if (config?.vaultConfigs && !Array.isArray(config.vaultConfigs)) { - throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_TYPE_FOR_CONFIG, [VAULT]) + throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_TYPE_FOR_CONFIG, [CONFIG.VAULT]) } if (config?.connectionConfigs && !Array.isArray(config?.connectionConfigs)) { - throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_TYPE_FOR_CONFIG, [CONNECTION]) + throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_TYPE_FOR_CONFIG, [CONFIG.CONNECTION]) } } else { @@ -222,7 +222,7 @@ export const validateVaultConfig = (vaultConfig: VaultConfig, logLevel: LogLevel throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_ENV, [vaultConfig?.vaultId]); } if (vaultConfig?.credentials) { - validateCredentialsWithId(vaultConfig.credentials, VAULT, VAULT_ID, vaultConfig.vaultId, logLevel); + validateCredentialsWithId(vaultConfig.credentials, CONFIG.VAULT, CONFIG.VAULT_ID, vaultConfig.vaultId, logLevel); } } else { throw new SkyflowError(SKYFLOW_ERROR_CODE.EMPTY_VAULT_CONFIG); @@ -248,7 +248,7 @@ export const validateUpdateVaultConfig = (vaultConfig: VaultConfig, logLevel: Lo throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_ENV, [vaultConfig?.vaultId]); } if (vaultConfig?.credentials) { - validateCredentialsWithId(vaultConfig.credentials, VAULT, VAULT_ID, vaultConfig.vaultId, logLevel); + validateCredentialsWithId(vaultConfig.credentials, CONFIG.VAULT, CONFIG.VAULT_ID, vaultConfig.vaultId, logLevel); } } else { throw new SkyflowError(SKYFLOW_ERROR_CODE.EMPTY_VAULT_CONFIG); @@ -354,7 +354,7 @@ export const validateConnectionConfig = (connectionConfig: ConnectionConfig, log } if (connectionConfig?.credentials) { - validateCredentialsWithId(connectionConfig.credentials, CONNECTION, CONNECTION_ID, connectionConfig.connectionId, logLevel); + validateCredentialsWithId(connectionConfig.credentials, CONFIG.CONNECTION, CONFIG.CONNECTION_ID, connectionConfig.connectionId, logLevel); } } else { throw new SkyflowError(SKYFLOW_ERROR_CODE.EMPTY_CONNECTION_CONFIG) @@ -384,7 +384,7 @@ export const validateUpdateConnectionConfig = (connectionConfig: ConnectionConfi } if (connectionConfig?.credentials) { - validateCredentialsWithId(connectionConfig.credentials, CONNECTION, CONNECTION_ID, connectionConfig.connectionId, logLevel); + validateCredentialsWithId(connectionConfig.credentials, CONFIG.CONNECTION, CONFIG.CONNECTION_ID, connectionConfig.connectionId, logLevel); } } else { throw new SkyflowError(SKYFLOW_ERROR_CODE.EMPTY_CONNECTION_CONFIG) @@ -618,12 +618,12 @@ export const validateUpdateRequest = (updateRequest: UpdateRequest, updateOption throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_TYPE_OF_UPDATE_DATA); } - if (updateRequest?.data && !Object.prototype.hasOwnProperty.call(updateRequest.data, SKYFLOW_ID)) { + if (updateRequest?.data && !Object.prototype.hasOwnProperty.call(updateRequest.data, SKYFLOW.ID)) { printLog(logs.errorLogs.EMPTY_SKYFLOW_ID_IN_UPDATE, MessageType.ERROR, logLevel); throw new SkyflowError(SKYFLOW_ERROR_CODE.MISSING_SKYFLOW_ID_IN_UPDATE); } - if (updateRequest?.data[SKYFLOW_ID] && typeof updateRequest.data[SKYFLOW_ID] !== 'string' || (updateRequest.data[SKYFLOW_ID] as string).trim().length === 0) { + if (updateRequest?.data[SKYFLOW.ID] && typeof updateRequest.data[SKYFLOW.ID] !== 'string' || (updateRequest.data[SKYFLOW.ID] as string).trim().length === 0) { printLog(logs.errorLogs.INVALID_SKYFLOW_ID_IN_UPDATE, MessageType.ERROR, logLevel); throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_SKYFLOW_ID_IN_UPDATE); } diff --git a/src/vault/client/index.ts b/src/vault/client/index.ts index 36ab4fcd..1f57df63 100644 --- a/src/vault/client/index.ts +++ b/src/vault/client/index.ts @@ -6,7 +6,7 @@ import { Strings } from "../../ _generated_/rest/api/resources/strings/client/Cl import { Tokens } from "../../ _generated_/rest/api/resources/tokens/client/Client"; import SkyflowError from "../../error"; import errorMessages from "../../error/messages"; -import { AuthInfo, AuthType, LogLevel, MessageType, printLog, TYPES } from "../../utils/index"; +import { AuthInfo, AuthType, LogLevel, MessageType, printLog, TYPES, HTTP_HEADER, CONTENT_TYPE, BOOLEAN_STRING, HTTP_STATUS_CODE } from "../../utils/index"; import { isExpired } from "../../utils/jwt-utils"; import logs from "../../utils/logs"; import Credentials from "../config/credentials"; @@ -132,11 +132,11 @@ class VaultClient { const isNewFormat = (err as SkyflowApiErrorNewFormat).rawResponse !== undefined; if (isNewFormat) { const headers = (err as SkyflowApiErrorNewFormat).rawResponse?.headers; - const contentType = headers?.get('content-type'); - const requestId = headers?.get('x-request-id') || ''; - const errorFromClientHeader = headers?.get('error-from-client'); + const contentType = headers?.get(HTTP_HEADER.CONTENT_TYPE_LOWER); + const requestId = headers?.get(HTTP_HEADER.X_REQUEST_ID) || ''; + const errorFromClientHeader = headers?.get(HTTP_HEADER.ERROR_FROM_CLIENT); const errorFromClient = errorFromClientHeader - ? String(errorFromClientHeader).toLowerCase() === 'true' + ? String(errorFromClientHeader).toLowerCase() === BOOLEAN_STRING.TRUE : undefined; return { @@ -147,14 +147,14 @@ class VaultClient { }; } else { const headers = (err as SkyflowApiErrorLegacy).headers || {}; - const contentType = headers.get('content-type'); - const requestId = headers.get('x-request-id') || ''; + const contentType = headers.get(HTTP_HEADER.CONTENT_TYPE_LOWER); + const requestId = headers.get(HTTP_HEADER.X_REQUEST_ID) || ''; - const errorFromClientHeader = headers.get('error-from-client'); + const errorFromClientHeader = headers.get(HTTP_HEADER.ERROR_FROM_CLIENT); const errorFromClient = errorFromClientHeader - ? String(errorFromClientHeader).toLowerCase() === 'true' + ? String(errorFromClientHeader).toLowerCase() === BOOLEAN_STRING.TRUE : undefined; return { @@ -175,9 +175,9 @@ class VaultClient { : (err as SkyflowApiErrorLegacy).body?.error; if (contentType) { - if (contentType.includes('application/json')) { + if (contentType.includes(CONTENT_TYPE.APPLICATION_JSON)) { this.handleJsonError(err as SkyflowApiErrorNewFormat | SkyflowApiErrorLegacy, data, requestId, reject, errorFromClient); - } else if (contentType.includes('text/plain')) { + } else if (contentType.includes(CONTENT_TYPE.TEXT_PLAIN)) { this.handleTextError(err as SkyflowApiErrorNewFormat | SkyflowApiErrorLegacy, data, requestId, reject, errorFromClient); } else { this.handleGenericError(err as SkyflowApiErrorNewFormat | SkyflowApiErrorLegacy, requestId, reject, errorFromClient); @@ -353,7 +353,7 @@ class VaultClient { ) { printLog(description, MessageType.ERROR, this.getLogLevel()); reject(new SkyflowError({ - http_code: isNewError ? (err?.statusCode ?? err?.body?.error?.http_code ?? 400) : err?.body?.error?.http_code ?? 400, + http_code: isNewError ? (err?.statusCode ?? err?.body?.error?.http_code ?? HTTP_STATUS_CODE.BAD_REQUEST) : err?.body?.error?.http_code ?? HTTP_STATUS_CODE.BAD_REQUEST, message: description, request_ID: requestId, grpc_code: grpcCode, diff --git a/src/vault/controller/connections/index.ts b/src/vault/controller/connections/index.ts index c18abe22..ccdda37b 100644 --- a/src/vault/controller/connections/index.ts +++ b/src/vault/controller/connections/index.ts @@ -1,5 +1,5 @@ //imports -import { fillUrlWithPathAndQueryParams, generateSDKMetrics, getBearerToken, LogLevel, MessageType, RequestMethod, parameterizedString, printLog, SDK_METRICS_HEADER_KEY, SKYFLOW_AUTH_HEADER_KEY, REQUEST_ID_KEY, TYPES } from "../../../utils"; +import { fillUrlWithPathAndQueryParams, generateSDKMetrics, getBearerToken, LogLevel, MessageType, RequestMethod, parameterizedString, printLog, SDK, SKYFLOW, REQUEST, TYPES, HTTP_HEADER, CONTENT_TYPE } from "../../../utils"; import InvokeConnectionRequest from "../../model/request/inkove"; import logs from "../../../utils/logs"; import { validateInvokeConnectionRequest } from "../../../utils/validations"; @@ -19,10 +19,10 @@ class ConnectionController { private buildInvokeConnectionBody(invokeRequest: InvokeConnectionRequest){ let requestBody; - const contentType = invokeRequest.headers?.['Content-Type'] || 'application/json'; - if (contentType === 'application/json') { + const contentType = invokeRequest.headers?.[HTTP_HEADER.CONTENT_TYPE] || CONTENT_TYPE.APPLICATION_JSON; + if (contentType === CONTENT_TYPE.APPLICATION_JSON) { requestBody = JSON.stringify(invokeRequest.body); - } else if (contentType === 'application/x-www-form-urlencoded') { + } else if (contentType === CONTENT_TYPE.APPLICATION_X_WWW_FORM_URLENCODED) { const urlSearchParams = new URLSearchParams(); Object.entries(invokeRequest.body || {}).forEach(([key, value]) => { if (typeof value === 'object' && value !== null) { @@ -52,8 +52,8 @@ class ConnectionController { getBearerToken(this.client.getCredentials(), this.logLevel).then((token) => { printLog(parameterizedString(logs.infoLogs.EMIT_REQUEST, TYPES.INVOKE_CONNECTION), MessageType.LOG, this.logLevel); const sdkHeaders = {}; - sdkHeaders[SKYFLOW_AUTH_HEADER_KEY] = token.key; - sdkHeaders[SDK_METRICS_HEADER_KEY] = JSON.stringify(generateSDKMetrics()); + sdkHeaders[SKYFLOW.AUTH_HEADER_KEY] = token.key; + sdkHeaders[SDK.METRICS_HEADER_KEY] = JSON.stringify(generateSDKMetrics()); fetch(filledUrl, { method: invokeRequest.method || RequestMethod.POST, @@ -77,7 +77,7 @@ class ConnectionController { }) .then(({headers, body}) => { printLog(logs.infoLogs.INVOKE_CONNECTION_REQUEST_RESOLVED, MessageType.LOG, this.logLevel); - const requestId = headers?.get(REQUEST_ID_KEY) || ''; + const requestId = headers?.get(REQUEST.ID_KEY) || ''; const invokeConnectionResponse = new InvokeConnectionResponse({ data: body, metadata: { requestId }, diff --git a/src/vault/controller/detect/index.ts b/src/vault/controller/detect/index.ts index 83672c11..72b040ce 100644 --- a/src/vault/controller/detect/index.ts +++ b/src/vault/controller/detect/index.ts @@ -5,7 +5,7 @@ import { DeidentifyTextRequest as DeidentifyTextRequest2,DeidentifyAudioRequest, import { DeidentifyFileRequest as DeidentifyFileRequest2} from "../../../ _generated_/rest/api"; import { TokenType } from "../../../ _generated_/rest/api"; -import { DeidenitfyFileRequestTypes, generateSDKMetrics, getBearerToken, MessageType, parameterizedString, printLog, removeSDKVersion, SDK_METRICS_HEADER_KEY, TYPES } from "../../../utils"; +import { DeidenitfyFileRequestTypes, generateSDKMetrics, getBearerToken, MessageType, parameterizedString, printLog, removeSDKVersion, SDK, TYPES, HTTP_HEADER, DETECT_STATUS, FILE_EXTENSION, FILE_FORMAT_TYPE, FILE_PROCESSING, ENCODING_TYPE } from "../../../utils"; import logs from "../../../utils/logs"; import { validateDeIdentifyTextRequest, validateReidentifyTextRequest, validateDeidentifyFileRequest, validateGetDetectRunRequest } from "../../../utils/validations"; import VaultClient from "../../client"; @@ -30,6 +30,9 @@ import { DeidentifyFileDetectRunResponse, DeidentifyFileOutput, DetectTextRespon class DetectController { private client: VaultClient; + success=DETECT_STATUS.SUCCESS; + inProgress=DETECT_STATUS.IN_PROGRESS; + failed=DETECT_STATUS.FAILED; private waitTime: number = 64; @@ -38,7 +41,7 @@ class DetectController { } private createSdkHeaders() { - return { [SDK_METRICS_HEADER_KEY]: JSON.stringify(generateSDKMetrics()) }; + return { [SDK.METRICS_HEADER_KEY]: JSON.stringify(generateSDKMetrics()) }; } private async getFileFromRequest(request: DeidentifyFileRequest): Promise { @@ -58,7 +61,7 @@ class DetectController { private async getBase64FileContent(file: File){ const arrayBuffer = await file.arrayBuffer(); const buffer = Buffer.from(arrayBuffer); - const base64String = buffer.toString('base64'); + const base64String = buffer.toString(ENCODING_TYPE.BASE64); return base64String; } @@ -106,7 +109,7 @@ class DetectController { vault_id: this.client.vaultId, file: { base64: base64String, - data_format: "txt", + data_format: FILE_FORMAT_TYPE.TXT, }, entity_types: options?.getEntities() as EntityType[], token_type: { @@ -125,7 +128,7 @@ class DetectController { var pdfRequest: DeidentifyPdfRequest = { file: { base64: base64String as string, - data_format: "pdf", + data_format: FILE_FORMAT_TYPE.PDF, }, vault_id: this.client.vaultId, entity_types: options?.getEntities() as EntityType[], @@ -271,7 +274,7 @@ class DetectController { private decodeBase64AndSaveToFile(base64Data: string, outputFilePath: string) { try { // Decode the base64 string - const buffer = Buffer.from(base64Data, 'base64'); + const buffer = Buffer.from(base64Data, ENCODING_TYPE.BASE64); // Write the decoded data to the specified file fs.writeFileSync(outputFilePath, buffer); @@ -301,12 +304,12 @@ class DetectController { const outputFilePath = path.join(outputDirectory, outputFileName); // Handle JSON files - if (processedFileExtension === 'json') { - const jsonData = Buffer.from(processedFile, 'base64').toString('utf-8'); + if (processedFileExtension === FILE_EXTENSION.JSON) { + const jsonData = Buffer.from(processedFile, ENCODING_TYPE.BASE64).toString(ENCODING_TYPE.UTF_8); fs.writeFileSync(outputFilePath, jsonData); - } else if ( processedFileExtension === 'mp3' || processedFileExtension === 'wav') { - const mp3Data = Buffer.from(processedFile, 'base64'); - fs.writeFileSync(outputFilePath, mp3Data, { encoding: 'binary' }); + } else if ( processedFileExtension === FILE_EXTENSION.MP3 || processedFileExtension === FILE_EXTENSION.WAV) { + const mp3Data = Buffer.from(processedFile, ENCODING_TYPE.BASE64); + fs.writeFileSync(outputFilePath, mp3Data, { encoding: ENCODING_TYPE.BINARY }); } else { // Handle other file types (e.g., images, PDFs, etc.) this.decodeBase64AndSaveToFile(processedFile, outputFilePath); @@ -321,9 +324,9 @@ class DetectController { var reqType: DeidenitfyFileRequestTypes if (Object.values(DeidentifyAudioRequestFileDataFormat).includes(format as DeidentifyAudioRequestFileDataFormat)){ reqType = DeidenitfyFileRequestTypes.AUDIO; - } else if (format.includes('pdf')){ + } else if (format.includes(DeidenitfyFileRequestTypes.PDF.toLowerCase())){ reqType = DeidenitfyFileRequestTypes.PDF - } else if (format.includes('txt')){ + } else if (format.includes(DeidenitfyFileRequestTypes.TEXT.toLowerCase())){ reqType = DeidenitfyFileRequestTypes.TEXT } else if (Object.values(DeidentifyImageRequestFileDataFormat).includes(format as DeidentifyImageRequestFileDataFormat)){ reqType = DeidenitfyFileRequestTypes.IMAGE; @@ -348,8 +351,8 @@ class DetectController { const poll = () => { this.client.filesAPI.getRun(runId, req) - .then((response: DeidentifyStatusResponse) => { - if (response.status?.toUpperCase() === 'IN_PROGRESS' + .then((response: DeidentifyStatusResponse) => { + if (response.status?.toUpperCase() === this.inProgress ) { if (currentWaitTime >= maxWaitTime) { resolve({ runId }); // Resolve with runId if max wait time is exceeded @@ -367,10 +370,10 @@ class DetectController { poll(); }, waitTime * 1000); } - } else if (response.status?.toUpperCase() === 'SUCCESS') { + } else if (response.status?.toUpperCase() === this.success) { resolve([response, runId]); // Resolve with the processed file response and runId } - else if (response.status?.toUpperCase() === 'FAILED') { + else if (response.status?.toUpperCase() === this.failed) { reject(new SkyflowError(SKYFLOW_ERROR_CODE.INTERNAL_SERVER_ERROR, [response.message])); } }) @@ -466,10 +469,10 @@ class DetectController { let file: File | undefined = undefined; if (base64String && extension) { - const buffer = Buffer.from(base64String, 'base64'); + const buffer = Buffer.from(base64String, ENCODING_TYPE.BASE64); const fileName = `deidentified.${extension}`; - file = new File([buffer], fileName); - } + file = new File([buffer], fileName); +} return new DeidentifyFileResponse({ fileBase64: base64String, @@ -483,7 +486,7 @@ class DetectController { pageCount: data.pages ?? 0, slideCount: data.slides ?? 0, entities: (data.output || []) - .filter((fileObject: DeidentifyFileOutput) => fileObject.processedFileType === 'entities') + .filter((fileObject: DeidentifyFileOutput) => fileObject.processedFileType === FILE_PROCESSING.ENTITIES) .map((fileObject: DeidentifyFileOutput) => ({ file: fileObject.processedFile as string, extension: fileObject.processedFileExtension as string, @@ -709,13 +712,13 @@ class DetectController { } promiseReq.then(([data, runId]) => { - if(runId && data.status === "IN_PROGRESS") { + if(runId && data.status === this.inProgress) { resolve(new DeidentifyFileResponse({ runId: runId, status: data.status, })); } - if (options?.getOutputDirectory() && data.status === "SUCCESS") { + if (options?.getOutputDirectory() && data.status === this.success) { this.processDeidentifyFileResponse(data, options.getOutputDirectory() as string, fileBaseName); } const deidentifiedFileResponse = this.parseDeidentifyFileResponse(data, runId, data.status); diff --git a/src/vault/controller/vault/index.ts b/src/vault/controller/vault/index.ts index eb6aecc6..6f1619b0 100644 --- a/src/vault/controller/vault/index.ts +++ b/src/vault/controller/vault/index.ts @@ -22,7 +22,7 @@ import FileUploadResponse from '../../model/response/file-upload'; import TokenizeResponse from '../../model/response/tokenize'; import TokenizeRequest from '../../model/request/tokenize'; import { InsertResponseType, ParsedDetokenizeResponse, ParsedInsertBatchResponse, RecordsResponse, SkyflowIdResponse, StringKeyValueMapType, TokenizeRequestType, TokensResponse } from '../../types'; -import { generateSDKMetrics, getBearerToken, MessageType, parameterizedString, printLog, TYPES, SDK_METRICS_HEADER_KEY, removeSDKVersion, RedactionType, SKYFLOW_ID, SkyflowRecordError } from '../../../utils'; +import { generateSDKMetrics, getBearerToken, MessageType, parameterizedString, printLog, TYPES, SDK, removeSDKVersion, RedactionType, SKYFLOW, SkyflowRecordError, HTTP_STATUS_CODE, HTTP_HEADER, CONTENT_TYPE, ENCODING_TYPE } from '../../../utils'; import GetColumnRequest from '../../model/request/get-column'; import logs from '../../../utils/logs'; import VaultClient from '../../client'; @@ -40,7 +40,7 @@ class VaultController { } private createSdkHeaders() { - return { [SDK_METRICS_HEADER_KEY]: JSON.stringify(generateSDKMetrics()) }; + return { [SDK.METRICS_HEADER_KEY]: JSON.stringify(generateSDKMetrics()) }; } private handleRecordsResponse(records?: Record[]): Record[] { @@ -268,8 +268,8 @@ class VaultController { // Validation checks validateUpdateRequest(request, options, this.client.getLogLevel()); - const skyflowId = request.data[SKYFLOW_ID]; - delete request.data[SKYFLOW_ID]; + const skyflowId = request.data[SKYFLOW.ID]; + delete request.data[SKYFLOW.ID]; const record = { fields: request.data, tokens: options?.getTokens() }; const strictMode = options?.getTokenMode() ? options?.getTokenMode() : V1Byot.Disable; const updateData: RecordServiceUpdateRecordBody = { @@ -422,14 +422,14 @@ class VaultController { const fileBuffer = fs.readFileSync(options.getFilePath()!); fileName = path.basename(options.getFilePath()!); fileBlob = new File([fileBuffer], fileName, { - type: 'application/json' + type: CONTENT_TYPE.APPLICATION_JSON }); } else if (options?.getBase64()) { - const buffer = Buffer.from(options.getBase64()!, 'base64'); + const buffer = Buffer.from(options.getBase64()!, ENCODING_TYPE.BASE64); fileName = options.getFileName()!; fileBlob = new File([buffer], fileName, { - type: 'application/json' + type: CONTENT_TYPE.APPLICATION_JSON }); } diff --git a/src/vault/skyflow/index.ts b/src/vault/skyflow/index.ts index 85b33427..c65b549e 100644 --- a/src/vault/skyflow/index.ts +++ b/src/vault/skyflow/index.ts @@ -1,4 +1,4 @@ -import { CONNECTION_ID, CONTROLLER_TYPES, CREDENTIALS, Env, getVaultURL, ISkyflowError, LOGLEVEL, LogLevel, MessageType, parameterizedString, printLog, VAULT_ID } from "../../utils"; +import { CONFIG, CONTROLLER_TYPES, Env, getVaultURL, ISkyflowError, LogLevel, MessageType, parameterizedString, printLog } from "../../utils"; import ConnectionConfig from "../config/connection"; import VaultConfig from "../config/vault"; import { SkyflowConfig, ClientObj } from "../types"; @@ -65,13 +65,13 @@ class Skyflow { addVaultConfig(config: VaultConfig) { validateVaultConfig(config, this.logLevel); - this.throwErrorIfIdExits(config?.vaultId, this.vaultClients, VAULT_ID); + this.throwErrorIfIdExits(config?.vaultId, this.vaultClients, CONFIG.VAULT_ID); this.addVaultClient(config, this.vaultClients); } addConnectionConfig(config: ConnectionConfig) { validateConnectionConfig(config, this.logLevel); - this.throwErrorIfIdExits(config?.connectionId, this.connectionClients, CONNECTION_ID); + this.throwErrorIfIdExits(config?.connectionId, this.connectionClients, CONFIG.CONNECTION_ID); this.addConnectionClient(config, this.connectionClients); } @@ -100,28 +100,28 @@ class Skyflow { updateVaultConfig(config: VaultConfig) { validateUpdateVaultConfig(config, this.logLevel); - this.updateVaultClient(config, this.vaultClients, VAULT_ID); + this.updateVaultClient(config, this.vaultClients, CONFIG.VAULT_ID); } updateConnectionConfig(config: ConnectionConfig) { validateUpdateConnectionConfig(config, this.logLevel); - this.updateConnectionClient(config, this.connectionClients, CONNECTION_ID); + this.updateConnectionClient(config, this.connectionClients, CONFIG.CONNECTION_ID); } getVaultConfig(vaultId: string) { - return this.getConfig(vaultId, this.vaultClients, VAULT_ID); + return this.getConfig(vaultId, this.vaultClients, CONFIG.VAULT_ID); } removeVaultConfig(vaultId: string) { - this.removeConfig(vaultId, this.vaultClients, VAULT_ID); + this.removeConfig(vaultId, this.vaultClients, CONFIG.VAULT_ID); } getConnectionConfig(connectionId: string) { - return this.getConfig(connectionId, this.connectionClients, CONNECTION_ID); + return this.getConfig(connectionId, this.connectionClients, CONFIG.CONNECTION_ID); } removeConnectionConfig(connectionId: string) { - this.removeConfig(connectionId, this.connectionClients, CONNECTION_ID); + this.removeConfig(connectionId, this.connectionClients, CONFIG.CONNECTION_ID); } private throwSkyflowError(idKey: string, errorMapping: { [key: string]: ISkyflowError }, params?: string[]) { @@ -133,8 +133,8 @@ class Skyflow { private throwErrorIfIdExits(id: string, clients: ClientObj, idKey: string) { const errorMapping = { - [VAULT_ID]: SKYFLOW_ERROR_CODE.VAULT_ID_EXITS_IN_CONFIG_LIST, - [CONNECTION_ID]: SKYFLOW_ERROR_CODE.CONNECTION_ID_EXITS_IN_CONFIG_LIST, + [CONFIG.VAULT_ID]: SKYFLOW_ERROR_CODE.VAULT_ID_EXITS_IN_CONFIG_LIST, + [CONFIG.CONNECTION_ID]: SKYFLOW_ERROR_CODE.CONNECTION_ID_EXITS_IN_CONFIG_LIST, }; if(Object.keys(clients).includes(id)){ printLog(parameterizedString(logs.infoLogs[`${idKey}_CONFIG_EXISTS`], [id]), MessageType.ERROR, this.logLevel); @@ -144,8 +144,8 @@ class Skyflow { private throwErrorForUnknownId(id: string, idKey: string) { const errorMapping = { - [VAULT_ID]: SKYFLOW_ERROR_CODE.VAULT_ID_NOT_IN_CONFIG_LIST, - [CONNECTION_ID]: SKYFLOW_ERROR_CODE.CONNECTION_ID_NOT_IN_CONFIG_LIST, + [CONFIG.VAULT_ID]: SKYFLOW_ERROR_CODE.VAULT_ID_NOT_IN_CONFIG_LIST, + [CONFIG.CONNECTION_ID]: SKYFLOW_ERROR_CODE.CONNECTION_ID_NOT_IN_CONFIG_LIST, }; printLog(parameterizedString(logs.infoLogs[`${idKey}_CONFIG_DOES_NOT_EXIST`], [id]), MessageType.ERROR, this.logLevel); this.throwSkyflowError(idKey, errorMapping, [id]); @@ -153,16 +153,16 @@ class Skyflow { private throwErrorForEmptyClients(idKey: string) { const errorMapping = { - [VAULT_ID]: SKYFLOW_ERROR_CODE.EMPTY_VAULT_CLIENTS, - [CONNECTION_ID]: SKYFLOW_ERROR_CODE.EMPTY_CONNECTION_CLIENTS, + [CONFIG.VAULT_ID]: SKYFLOW_ERROR_CODE.EMPTY_VAULT_CLIENTS, + [CONFIG.CONNECTION_ID]: SKYFLOW_ERROR_CODE.EMPTY_CONNECTION_CLIENTS, }; this.throwSkyflowError(idKey, errorMapping); } private throwErrorForEmptyId(idKey: string) { const errorMapping = { - [VAULT_ID]: SKYFLOW_ERROR_CODE.EMPTY_VAULT_ID_VALIDATION, - [CONNECTION_ID]: SKYFLOW_ERROR_CODE.EMPTY_CONNECTION_ID_VALIDATION, + [CONFIG.VAULT_ID]: SKYFLOW_ERROR_CODE.EMPTY_VAULT_ID_VALIDATION, + [CONFIG.CONNECTION_ID]: SKYFLOW_ERROR_CODE.EMPTY_CONNECTION_ID_VALIDATION, }; this.throwSkyflowError(idKey, errorMapping); } @@ -183,7 +183,7 @@ class Skyflow { throw new SkyflowError(SKYFLOW_ERROR_CODE.INVALID_LOG_LEVEL); } this.logLevel = logLevel; - this.updateClients(LOGLEVEL); + this.updateClients(CONFIG.LOGLEVEL); } getLogLevel() { @@ -195,7 +195,7 @@ class Skyflow { throw new SkyflowError(SKYFLOW_ERROR_CODE.EMPTY_CREDENTIALS); validateSkyflowCredentials(credentials); this.commonCredentials = credentials; - this.updateClients(CREDENTIALS); + this.updateClients(CONFIG.CREDENTIALS); } getSkyflowCredentials() { @@ -203,15 +203,15 @@ class Skyflow { } vault(vaultId?: string) { - return this.getClient(vaultId, this.vaultClients, VAULT_ID, CONTROLLER_TYPES.VAULT) as VaultController; + return this.getClient(vaultId, this.vaultClients, CONFIG.VAULT_ID, CONTROLLER_TYPES.VAULT) as VaultController; } detect(vaultId?: string) { - return this.getClient(vaultId, this.vaultClients, VAULT_ID, CONTROLLER_TYPES.DETECT) as DetectController; + return this.getClient(vaultId, this.vaultClients, CONFIG.VAULT_ID, CONTROLLER_TYPES.DETECT) as DetectController; } connection(connectionId?: string) { - return this.getClient(connectionId, this.connectionClients, CONNECTION_ID, CONTROLLER_TYPES.CONNECTION) as ConnectionController; + return this.getClient(connectionId, this.connectionClients, CONFIG.CONNECTION_ID, CONTROLLER_TYPES.CONNECTION) as ConnectionController; } private getClient( @@ -251,9 +251,9 @@ class Skyflow { private updateClient(updateType: string, list: ClientObj) { Object.values(list).forEach(clientConfig => { - if (updateType === LOGLEVEL) { + if (updateType === CONFIG.LOGLEVEL) { clientConfig.client.setLogLevel(this.logLevel); - } else if (updateType === CREDENTIALS) { + } else if (updateType === CONFIG.CREDENTIALS) { clientConfig.client.updateSkyflowCredentials(this.commonCredentials); } }); diff --git a/test/vault/controller/connection.test.js b/test/vault/controller/connection.test.js index 9e8a0ed8..5ed4a3ca 100644 --- a/test/vault/controller/connection.test.js +++ b/test/vault/controller/connection.test.js @@ -4,8 +4,8 @@ import { getBearerToken, LogLevel, RequestMethod, - SDK_METRICS_HEADER_KEY, - SKYFLOW_AUTH_HEADER_KEY, + SDK, + SKYFLOW, } from "../../../src/utils"; import { validateInvokeConnectionRequest } from "../../../src/utils/validations"; import VaultClient from "../../../src/vault/client"; @@ -69,8 +69,8 @@ describe("ConnectionController Tests", () => { body: JSON.stringify(request.body), headers: { ...request.headers, - [SKYFLOW_AUTH_HEADER_KEY]: token.key, - [SDK_METRICS_HEADER_KEY]: JSON.stringify(generateSDKMetrics()), + [SKYFLOW.AUTH_HEADER_KEY]: token.key, + [SDK.METRICS_HEADER_KEY]: JSON.stringify(generateSDKMetrics()), }, }); }); diff --git a/test/vault/controller/detect.test.js b/test/vault/controller/detect.test.js index bb313469..f062c31f 100644 --- a/test/vault/controller/detect.test.js +++ b/test/vault/controller/detect.test.js @@ -4,7 +4,7 @@ import DeidentifyTextResponse from '../../../src/vault/model/response/deidentify import ReidentifyTextResponse from '../../../src/vault/model/response/reidentify-text'; import DeidentifyFileRequest from '../../../src/vault/model/request/deidentify-file'; import DeidentifyFileOptions from '../../../src/vault/model/options/deidentify-file'; -import { TYPES } from '../../../src/utils'; +import { DETECT_STATUS, ENCODING_TYPE, TYPES } from '../../../src/utils'; import fs from 'fs'; jest.mock('../../../src/utils', () => ({ @@ -33,6 +33,34 @@ jest.mock('../../../src/utils', () => ({ DOCUMENT: 'DOCUMENT', FILE: 'FILE', }, + DETECT_STATUS: { + IN_PROGRESS: 'IN_PROGRESS', + SUCCESS: 'SUCCESS', + FAILED: 'FAILED', + }, + SDK: { + METRICS_HEADER_KEY: 'sky-metadata', + }, + FILE_EXTENSION: { + JSON: 'json', + MP3: 'mp3', + WAV: 'wav', + }, + FILE_FORMAT_TYPE: { + TXT: 'txt', + PDF: 'pdf', + }, + FILE_PROCESSING: { + PROCESSED_PREFIX: 'processed-', + DEIDENTIFIED_PREFIX: 'deidentified.', + ENTITIES: 'entities', + }, + ENCODING_TYPE: { + UTF8: 'utf8', + BASE64: 'base64', + BINARY: 'binary', + UTF_8: 'utf-8', + }, generateSDKMetrics: jest.fn().mockReturnValue({ sdk: 'metrics' }), getBearerToken: jest.fn().mockResolvedValue(Promise.resolve('your-bearer-token')), })); @@ -904,52 +932,70 @@ describe('deidentifyFile', () => { expect(result.status).toBe('SUCCESS'); }); - test('should successfully deidentify a text file and poll until SUCCESS', async () => { - const file = new File(['doc content'], 'test.txt'); - const deidentifyFileReq = new DeidentifyFileRequest({file}); - const options = new DeidentifyFileOptions(); - - mockVaultClient.filesAPI.deidentifyText.mockImplementation(() => ({ - withRawResponse: jest.fn().mockResolvedValue({ - data: { run_id: 'docRunId' }, - rawResponse: { headers: { get: jest.fn().mockReturnValue('request-id-111') } }, - }), - })); + test('should successfully deidentify a text file and poll until SUCCESS', async () => { + // 1. Data Setup + const file = new File(['doc content'], 'test.txt', { type: 'text/plain' }); + const deidentifyFileReq = new DeidentifyFileRequest({ file }); + const options = new DeidentifyFileOptions(); + options.setOutputDirectory('/mock/output/directory'); + + // 2. Mock File System (using spies to verify calls) + const existsSpy = jest.spyOn(fs, 'existsSync').mockReturnValue(true); + const writeSpy = jest.spyOn(fs, 'writeFileSync').mockImplementation(() => {}); + + // 3. Mock deidentifyFile (The specific method causing the TypeError) + mockVaultClient.filesAPI.deidentifyFile = jest.fn().mockImplementation(() => ({ + withRawResponse: jest.fn().mockResolvedValue({ + data: { run_id: 'docRunId' }, + rawResponse: { + headers: { + get: jest.fn().mockReturnValue('request-id-111') + } + }, + }), + })); - mockVaultClient.filesAPI.getRun - .mockResolvedValueOnce({ status: 'IN_PROGRESS' }) - .mockResolvedValueOnce({ - status: 'SUCCESS', - output: [ - { - processedFile: 'textProcessedFile', - processedFileType: 'text', - processedFileExtension: 'txt', - }, - ], - wordCharacterCount: { - wordCount: 7, - characterCount: 70, + mockVaultClient.filesAPI.getRun = jest.fn() + .mockResolvedValueOnce({ status: 'IN_PROGRESS' }) + .mockResolvedValueOnce({ + status: 'SUCCESS', + output: [ + { + processedFile: Buffer.from('textProcessedFile').toString('base64'), + processedFileType: 'text', + processedFileExtension: 'txt', }, - size: 1024, - duration: 0, - pages: 1, - slides: 0, - run_id: 'textRunId', - }); + ], + wordCharacterCount: { + wordCount: 7, + characterCount: 70, + }, + size: 1024, + duration: 0, + pages: 1, + slides: 0, + run_id: 'docRunId', + }); - const promise = detectController.deidentifyFile(deidentifyFileReq, options); - await jest.runAllTimersAsync(); + const promise = detectController.deidentifyFile(deidentifyFileReq, options); - const result = await promise; - expect(result.fileBase64).toBe('textProcessedFile'); - expect(result.extension).toBe('txt'); - expect(result.wordCount).toBe(7); - expect(result.charCount).toBe(70); - expect(result.sizeInKb).toBe(1024); - expect(result.pageCount).toBe(1); - expect(result.status).toBe('SUCCESS'); - }); + // Fast-forward through the polling intervals + await jest.runAllTimersAsync(); + + const result = await promise; + + // 6. Assertions + expect(result.extension).toBe('txt'); + expect(result.wordCount).toBe(7); + expect(result.status).toBe('SUCCESS'); + + // Verify file system interactions + expect(existsSpy).toHaveBeenCalledWith(expect.stringContaining('/mock/output/directory')); + expect(writeSpy).toHaveBeenCalledWith( + expect.stringContaining('processed-test.txt'), + expect.any(Buffer) + ); +}); test('should successfully deidentify a generic file and poll until SUCCESS', async () => { const file = new File(['generic content'], 'test.abc', { type: 'application/octet-stream' }); @@ -999,64 +1045,57 @@ describe('deidentifyFile', () => { }); test('should successfully deidentify a PDF file and save processed file to output directory', async () => { + // 1. Clear any previous mock call data + jest.clearAllMocks(); + + const pdfFile = new File(['dummy content'], 'test.pdf', { type: 'application/pdf' }); + const pdfRequest = new DeidentifyFileRequest({file: pdfFile}); + + const mockOptions = new DeidentifyFileOptions(); + mockOptions.setWaitTime(16); + mockOptions.setOutputDirectory('/mock/output/directory'); + + // Mock API implementations... + mockVaultClient.filesAPI.deidentifyPdf.mockImplementation(() => ({ + withRawResponse: jest.fn().mockResolvedValue({ + data: { run_id: 'mockRunId' }, + rawResponse: { headers: { get: jest.fn().mockReturnValue('request-id-123') } }, + }), + })); + + mockVaultClient.filesAPI.getRun + .mockResolvedValueOnce({ status: 'IN_PROGRESS' }) + .mockResolvedValueOnce({ status: 'IN_PROGRESS' }) + .mockResolvedValueOnce({ + status: 'SUCCESS', + output: [{ + processedFile: Buffer.from('mockProcessedFileContent').toString('base64'), + processedFileType: 'pdf', + processedFileExtension: 'pdf', + }], + // ... (other mock data) + }); - const pdfFile = new File(['dummy content'], 'test.pdf', { type: 'application/pdf' }); - const pdfRequest = new DeidentifyFileRequest({file: pdfFile}); - - const mockOptions = new DeidentifyFileOptions(); - mockOptions.setWaitTime(16); - mockOptions.setOutputDirectory('/mock/output/directory'); - - // Mock the deidentifyPdf API call - mockVaultClient.filesAPI.deidentifyPdf.mockImplementation(() => ({ - withRawResponse: jest.fn().mockResolvedValue({ - data: { run_id: 'mockRunId' }, - rawResponse: { headers: { get: jest.fn().mockReturnValue('request-id-123') } }, - }), - })); - - // Mock the getRun API call for polling - mockVaultClient.filesAPI.getRun - .mockResolvedValueOnce({ status: 'IN_PROGRESS' }) - .mockResolvedValueOnce({ status: 'IN_PROGRESS' }) - .mockResolvedValueOnce({ - status: 'SUCCESS', - output: [ - { - processedFile: Buffer.from('mockProcessedFileContent').toString('base64'), - processedFileType: 'pdf', - processedFileExtension: 'pdf', - }, - ], - wordCharacterCount: { - wordCount: 100, - characterCount: 500, - }, - size: 1024, - duration: 0, - pages: 10, - slides: 0, - }); - - // Mock the file system to avoid actual file writes - jest.spyOn(fs, 'existsSync').mockImplementation((path) => path === '/mock/output/directory'); - jest.spyOn(fs, 'mkdirSync').mockImplementation(() => {}); - jest.spyOn(fs, 'writeFileSync').mockImplementation(() => {}); - - const promise = detectController.deidentifyFile(pdfRequest, mockOptions); - - await jest.runAllTimersAsync(); - - const result = await promise; - - // Assertions for the response - expect(result.extension).toBe('pdf'); - - // Assertions for processDeidentifyFileResponse - expect(fs.existsSync).toHaveBeenCalledWith('/mock/output/directory'); - expect(fs.writeFileSync).toHaveBeenCalledWith( - '/mock/output/directory/processed-test.pdf', - expect.any(Buffer) - ); - }); + // 2. Setup Spies + const existsSpy = jest.spyOn(fs, 'existsSync').mockReturnValue(true); + const mkdirSpy = jest.spyOn(fs, 'mkdirSync').mockImplementation(() => {}); + const writeSpy = jest.spyOn(fs, 'writeFileSync').mockImplementation(() => {}); + + // 3. START the execution + const promise = detectController.deidentifyFile(pdfRequest, mockOptions); + + // 4. ADVANCE timers so the polling intervals fire + await jest.runAllTimersAsync(); + + // 5. AWAIT the result + const result = await promise; + + // Assertions + expect(result.extension).toBe('pdf'); + expect(existsSpy).toHaveBeenCalledWith('/mock/output/directory'); + expect(writeSpy).toHaveBeenCalledWith( + expect.stringContaining('processed-test.pdf'), + expect.any(Buffer) + ); +}); }); \ No newline at end of file diff --git a/test/vault/controller/vault.test.js b/test/vault/controller/vault.test.js index 03a3cf6c..df6a8ea6 100644 --- a/test/vault/controller/vault.test.js +++ b/test/vault/controller/vault.test.js @@ -42,7 +42,23 @@ jest.mock('../../../src/utils', () => ({ MASKED: 'MASKED', REDACTED: 'REDACTED', }, - SKYFLOW_ID: 'skyflowId', + SDK: { + METRICS_HEADER_KEY: 'sky-metadata', + }, + SKYFLOW: { + ID: 'skyflowId', + }, + CONTENT_TYPE: { + APPLICATION_JSON: 'application/json', + APPLICATION_X_WWW_FORM_URLENCODED: 'application/x-www-form-urlencoded', + TEXT_PLAIN: 'text/plain', + }, + ENCODING_TYPE: { + UTF8: 'utf8', + BASE64: 'base64', + BINARY: 'binary', + UTF_8: 'utf-8', + }, TYPES: { INSERT: 'INSERT', INSERT_BATCH: 'INSERT_BATCH', From 68863e14291f31af5385c9c320ae50cb09d14471 Mon Sep 17 00:00:00 2001 From: Aadarsh Date: Tue, 27 Jan 2026 15:58:22 +0530 Subject: [PATCH 3/4] aadarsh-st/SK-2495-Fixed comments --- eslint.config.mjs | 2 +- src/utils/index.ts | 6 +++--- src/vault/controller/detect/index.ts | 13 +++++-------- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 263c2112..3f25a466 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -7,7 +7,7 @@ export default tseslint.config( languageOptions: { parser: tseslint.parser, parserOptions: { - projectSouce: true, + projectSource: true, tsconfigRootDir: import.meta.dirname, sourceType: "module", }, diff --git a/src/utils/index.ts b/src/utils/index.ts index 61b6b5a9..6c13c9cb 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -230,7 +230,7 @@ export const CONTENT_TYPE = { APPLICATION_JSON: 'application/json', APPLICATION_X_WWW_FORM_URLENCODED: 'application/x-www-form-urlencoded', TEXT_PLAIN: 'text/plain', -} as const; +} as const; // HTTP Headers export const HTTP_HEADER = { @@ -245,7 +245,7 @@ export const DETECT_STATUS = { IN_PROGRESS: 'IN_PROGRESS', SUCCESS: 'SUCCESS', FAILED: 'FAILED', -} as const; +} as const; // File Extensions export const FILE_EXTENSION = { @@ -287,7 +287,7 @@ export const JWT = { // API Key Prefix export const API_KEY = { PREFIX: 'sky-', -}as const ; +} as const; // URL Protocol export const URL_PROTOCOL = { diff --git a/src/vault/controller/detect/index.ts b/src/vault/controller/detect/index.ts index 72b040ce..bd85bb87 100644 --- a/src/vault/controller/detect/index.ts +++ b/src/vault/controller/detect/index.ts @@ -30,9 +30,6 @@ import { DeidentifyFileDetectRunResponse, DeidentifyFileOutput, DetectTextRespon class DetectController { private client: VaultClient; - success=DETECT_STATUS.SUCCESS; - inProgress=DETECT_STATUS.IN_PROGRESS; - failed=DETECT_STATUS.FAILED; private waitTime: number = 64; @@ -352,7 +349,7 @@ class DetectController { const poll = () => { this.client.filesAPI.getRun(runId, req) .then((response: DeidentifyStatusResponse) => { - if (response.status?.toUpperCase() === this.inProgress + if (response.status?.toUpperCase() === DETECT_STATUS.IN_PROGRESS ) { if (currentWaitTime >= maxWaitTime) { resolve({ runId }); // Resolve with runId if max wait time is exceeded @@ -370,10 +367,10 @@ class DetectController { poll(); }, waitTime * 1000); } - } else if (response.status?.toUpperCase() === this.success) { + } else if (response.status?.toUpperCase() === DETECT_STATUS.SUCCESS) { resolve([response, runId]); // Resolve with the processed file response and runId } - else if (response.status?.toUpperCase() === this.failed) { + else if (response.status?.toUpperCase() === DETECT_STATUS.FAILED) { reject(new SkyflowError(SKYFLOW_ERROR_CODE.INTERNAL_SERVER_ERROR, [response.message])); } }) @@ -712,13 +709,13 @@ class DetectController { } promiseReq.then(([data, runId]) => { - if(runId && data.status === this.inProgress) { + if(runId && data.status === DETECT_STATUS.IN_PROGRESS) { resolve(new DeidentifyFileResponse({ runId: runId, status: data.status, })); } - if (options?.getOutputDirectory() && data.status === this.success) { + if (options?.getOutputDirectory() && data.status === DETECT_STATUS.SUCCESS) { this.processDeidentifyFileResponse(data, options.getOutputDirectory() as string, fileBaseName); } const deidentifiedFileResponse = this.parseDeidentifyFileResponse(data, runId, data.status); From b4ecf5a3e540a089b7cc2e020da3d1db7ed04f03 Mon Sep 17 00:00:00 2001 From: Aadarsh Date: Tue, 27 Jan 2026 16:10:55 +0530 Subject: [PATCH 4/4] aadarsh-st/SK-2495 Updated message --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bf2a4658..fec5a2b3 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "eslint": "eslint '**/*.{js,ts}' --max-warnings 0", "prettier": "prettier --list-different '**/*.{js,ts}'", "lint": "npm run eslint", - "lint-fix": "prettier --write '**/*.{js,ts}' && eslint --fix '**/*.js'", + "lint-fix": "prettier --write '**/*.{js,ts}' && eslint --fix '**/*.{js,ts}'", "spellcheck": "cspell '**/*.{ts,js,md}'", "docs-gen": "typedoc && node scripts/docs-script/markdown-gen.js && npx ts-node scripts/docs-script/processMarkdown.ts" },