diff --git a/.gitignore b/.gitignore index 04761aa03e..a2ab84496b 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,4 @@ dist/ # TypeScript compiled files packages/**/lib +*.sqlite \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 4dd828bf98..3f764a86ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,6 +48,7 @@ "json-schema": "^0.4.0", "json-schema-to-ts": "^2.5.3", "jsonwebtoken": "^8.5.1", + "knex": "^2.1.0", "koa": "^2.13.4", "koa-bodyparser": "^4.3.0", "koa-compose": "^4.1.0", @@ -65,6 +66,7 @@ "sift": "^16.0.0", "socket.io": "^4.5.1", "socket.io-client": "^4.5.1", + "sqlite3": "^5.0.8", "superagent": "^7.1.6", "ts-loader": "^9.3.0", "ts-node": "^10.8.1", @@ -1855,7 +1857,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "dev": true + "devOptional": true }, "node_modules/@humanwhocodes/config-array": { "version": "0.9.5", @@ -2971,6 +2973,67 @@ "node": "^14.15.0 || >=16.0.0" } }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.9.tgz", + "integrity": "sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw==", + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -3553,7 +3616,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true, + "devOptional": true, "engines": { "node": ">= 6" } @@ -4303,8 +4366,7 @@ "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "node_modules/accepts": { "version": "1.3.8", @@ -4374,7 +4436,7 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", - "dev": true, + "devOptional": true, "dependencies": { "debug": "^4.1.0", "depd": "^1.1.2", @@ -4388,7 +4450,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, + "devOptional": true, "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -4541,14 +4603,13 @@ "node_modules/aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "dev": true + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" }, "node_modules/are-we-there-yet": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.0.tgz", "integrity": "sha512-0GWpv50YSOcLXaN6/FAKY3vfRbllXWV2xvfA/oKJF8pzFhWXPV+yjhJXDBbjscDYowv7Yw1A3uigpzn5iEGTyw==", - "dev": true, + "devOptional": true, "dependencies": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" @@ -6614,7 +6675,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true, "engines": { "node": ">=10" } @@ -6643,7 +6703,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, + "devOptional": true, "engines": { "node": ">=6" } @@ -6805,15 +6865,14 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true, "bin": { "color-support": "bin.js" } }, "node_modules/colorette": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", - "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==" + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", + "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==" }, "node_modules/colors": { "version": "1.0.3", @@ -6852,7 +6911,6 @@ "version": "9.3.0", "resolved": "https://registry.npmjs.org/commander/-/commander-9.3.0.tgz", "integrity": "sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw==", - "dev": true, "engines": { "node": "^12.20.0 || >=14" } @@ -6976,8 +7034,7 @@ "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" }, "node_modules/content-disposition": { "version": "0.5.4", @@ -7514,6 +7571,14 @@ "node": ">=8" } }, + "node_modules/detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "engines": { + "node": ">=8" + } + }, "node_modules/dezalgo": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", @@ -7630,9 +7695,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.160", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.160.tgz", - "integrity": "sha512-O1Z12YfyeX2LXYO7MdHIPazGXzLzQnr1ADW55U2ARQsJBPgfpJz3u+g3Mo2l1wSyfOCdiGqaX9qtV4XKZ0HNRA==" + "version": "1.4.161", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.161.tgz", + "integrity": "sha512-sTjBRhqh6wFodzZtc5Iu8/R95OkwaPNn7tj/TaDU5nu/5EFiQDtADGAXdR4tJcTEHlYfJpHqigzJqHvPgehP8A==" }, "node_modules/elliptic": { "version": "6.5.4", @@ -7803,7 +7868,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, + "devOptional": true, "engines": { "node": ">=6" } @@ -7823,7 +7888,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true + "devOptional": true }, "node_modules/error-ex": { "version": "1.3.2", @@ -8137,6 +8202,14 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "node_modules/esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", + "engines": { + "node": ">=6" + } + }, "node_modules/espree": { "version": "9.3.2", "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", @@ -8960,7 +9033,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, "dependencies": { "minipass": "^3.0.0" }, @@ -9009,7 +9081,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "dev": true, + "devOptional": true, "dependencies": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.3", @@ -9053,6 +9125,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/get-pkg-repo": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz", @@ -9146,6 +9226,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/getopts": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/getopts/-/getopts-2.3.0.tgz", + "integrity": "sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA==" + }, "node_modules/git-raw-commits": { "version": "2.0.11", "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz", @@ -9600,8 +9685,7 @@ "node_modules/has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" }, "node_modules/has-yarn": { "version": "2.1.0", @@ -9739,7 +9823,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "dev": true + "devOptional": true }, "node_modules/http-errors": { "version": "2.0.0", @@ -9768,7 +9852,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, + "devOptional": true, "dependencies": { "@tootallnate/once": "1", "agent-base": "6", @@ -9803,7 +9887,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "dev": true, + "devOptional": true, "dependencies": { "ms": "^2.0.0" } @@ -9913,7 +9997,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.8.19" } @@ -9922,7 +10006,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, + "devOptional": true, "engines": { "node": ">=8" } @@ -9931,7 +10015,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true + "devOptional": true }, "node_modules/inflation": { "version": "2.0.0", @@ -10051,9 +10135,9 @@ } }, "node_modules/interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", "engines": { "node": ">= 0.10" } @@ -10242,7 +10326,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "dev": true + "devOptional": true }, "node_modules/is-npm": { "version": "5.0.0", @@ -10804,6 +10888,64 @@ "node": ">=6" } }, + "node_modules/knex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/knex/-/knex-2.1.0.tgz", + "integrity": "sha512-vVsnD6UJdSJy55TvCXfFF9syfwyXNxfE9mvr2hJL/4Obciy2EPGoqjDpgRSlMruHuPWDOeYAG25nyrGvU+jJog==", + "dependencies": { + "colorette": "2.0.16", + "commander": "^9.1.0", + "debug": "4.3.4", + "escalade": "^3.1.1", + "esm": "^3.2.25", + "get-package-type": "^0.1.0", + "getopts": "2.3.0", + "interpret": "^2.2.0", + "lodash": "^4.17.21", + "pg-connection-string": "2.5.0", + "rechoir": "^0.8.0", + "resolve-from": "^5.0.0", + "tarn": "^3.0.2", + "tildify": "2.0.0" + }, + "bin": { + "knex": "bin/cli.js" + }, + "engines": { + "node": ">=12" + }, + "peerDependenciesMeta": { + "better-sqlite3": { + "optional": true + }, + "mysql": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-native": { + "optional": true + }, + "sqlite3": { + "optional": true + }, + "tedious": { + "optional": true + } + } + }, + "node_modules/knex/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "engines": { + "node": ">=8" + } + }, "node_modules/koa": { "version": "2.13.4", "resolved": "https://registry.npmjs.org/koa/-/koa-2.13.4.tgz", @@ -11757,7 +11899,7 @@ "version": "9.1.0", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", - "dev": true, + "devOptional": true, "dependencies": { "agentkeepalive": "^4.1.3", "cacache": "^15.2.0", @@ -11784,7 +11926,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", - "dev": true, + "devOptional": true, "dependencies": { "@gar/promisify": "^1.0.1", "semver": "^7.3.5" @@ -11794,7 +11936,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", - "dev": true, + "devOptional": true, "dependencies": { "mkdirp": "^1.0.4", "rimraf": "^3.0.2" @@ -11807,7 +11949,7 @@ "version": "15.3.0", "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", - "dev": true, + "devOptional": true, "dependencies": { "@npmcli/fs": "^1.0.0", "@npmcli/move-file": "^1.0.1", @@ -11836,7 +11978,7 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, + "devOptional": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -11856,7 +11998,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, + "devOptional": true, "dependencies": { "yallist": "^4.0.0" }, @@ -12303,7 +12445,6 @@ "version": "3.1.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", - "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -12315,7 +12456,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "dev": true, + "devOptional": true, "dependencies": { "minipass": "^3.0.0" }, @@ -12327,7 +12468,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", - "dev": true, + "devOptional": true, "dependencies": { "minipass": "^3.1.0", "minipass-sized": "^1.0.3", @@ -12344,7 +12485,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "dev": true, + "devOptional": true, "dependencies": { "minipass": "^3.0.0" }, @@ -12366,7 +12507,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "dev": true, + "devOptional": true, "dependencies": { "minipass": "^3.0.0" }, @@ -12378,7 +12519,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "dev": true, + "devOptional": true, "dependencies": { "minipass": "^3.0.0" }, @@ -12390,7 +12531,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -12403,7 +12543,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, "bin": { "mkdirp": "bin/cmd.js" }, @@ -13042,6 +13181,11 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, + "node_modules/node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==" + }, "node_modules/node-fetch": { "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", @@ -13084,7 +13228,7 @@ "version": "8.4.1", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", - "dev": true, + "devOptional": true, "dependencies": { "env-paths": "^2.2.0", "glob": "^7.1.4", @@ -13108,7 +13252,7 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, + "devOptional": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -13133,7 +13277,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "dev": true, "dependencies": { "abbrev": "1" }, @@ -13564,7 +13707,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "dev": true, + "devOptional": true, "dependencies": { "are-we-there-yet": "^3.0.0", "console-control-strings": "^1.1.0", @@ -13797,7 +13940,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, + "devOptional": true, "dependencies": { "aggregate-error": "^3.0.0" }, @@ -14361,6 +14504,11 @@ "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" }, + "node_modules/pg-connection-string": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", + "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -14580,13 +14728,13 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "dev": true + "devOptional": true }, "node_modules/promise-retry": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dev": true, + "devOptional": true, "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" @@ -15359,14 +15507,14 @@ } }, "node_modules/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", "dependencies": { - "resolve": "^1.1.6" + "resolve": "^1.20.0" }, "engines": { - "node": ">= 0.10" + "node": ">= 10.13.0" } }, "node_modules/redent": { @@ -15649,7 +15797,7 @@ "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "dev": true, + "devOptional": true, "engines": { "node": ">= 4" } @@ -15972,8 +16120,7 @@ "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, "node_modules/setprototypeof": { "version": "1.2.0", @@ -16045,6 +16192,25 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/shelljs/node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/shelljs/node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/shx": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz", @@ -16192,7 +16358,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", - "dev": true, + "devOptional": true, "dependencies": { "agent-base": "^6.0.2", "debug": "^4.3.3", @@ -16319,6 +16485,28 @@ "readable-stream": "^3.0.0" } }, + "node_modules/sqlite3": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.0.8.tgz", + "integrity": "sha512-f2ACsbSyb2D1qFFcqIXPfFscLtPVOWJr5GmUzYxf4W+0qelu5MWrR+FAQE1d5IUArEltBrzSDxDORG8P/IkqyQ==", + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "node-addon-api": "^4.2.0", + "tar": "^6.1.11" + }, + "optionalDependencies": { + "node-gyp": "8.x" + }, + "peerDependencies": { + "node-gyp": "8.x" + }, + "peerDependenciesMeta": { + "node-gyp": { + "optional": true + } + } + }, "node_modules/sqwish": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/sqwish/-/sqwish-0.2.2.tgz", @@ -16334,7 +16522,7 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", - "dev": true, + "devOptional": true, "dependencies": { "minipass": "^3.1.1" }, @@ -16569,7 +16757,6 @@ "version": "6.1.11", "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", - "dev": true, "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -16607,6 +16794,14 @@ "readable-stream": "^3.4.0" } }, + "node_modules/tarn": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.2.tgz", + "integrity": "sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/temp-dir": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", @@ -16779,6 +16974,14 @@ "readable-stream": "3" } }, + "node_modules/tildify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz", + "integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==", + "engines": { + "node": ">=8" + } + }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -17126,7 +17329,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "dev": true, + "devOptional": true, "dependencies": { "unique-slug": "^2.0.0" } @@ -17135,7 +17338,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", - "dev": true, + "devOptional": true, "dependencies": { "imurmurhash": "^0.1.4" } @@ -17472,14 +17675,6 @@ "node": ">= 10" } }, - "node_modules/webpack-cli/node_modules/interpret": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", - "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", - "engines": { - "node": ">= 0.10" - } - }, "node_modules/webpack-cli/node_modules/rechoir": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", @@ -17588,7 +17783,6 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } @@ -19205,7 +19399,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "dev": true + "devOptional": true }, "@humanwhocodes/config-array": { "version": "0.9.5", @@ -20120,6 +20314,60 @@ "write-file-atomic": "^3.0.3" } }, + "@mapbox/node-pre-gyp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.9.tgz", + "integrity": "sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw==", + "requires": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "dependencies": { + "are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, + "gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + } + }, + "npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "requires": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + } + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -20609,7 +20857,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true + "devOptional": true }, "@tsconfig/node10": { "version": "1.0.9", @@ -21252,8 +21500,7 @@ "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "accepts": { "version": "1.3.8", @@ -21304,7 +21551,7 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", - "dev": true, + "devOptional": true, "requires": { "debug": "^4.1.0", "depd": "^1.1.2", @@ -21315,7 +21562,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, + "devOptional": true, "requires": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -21424,14 +21671,13 @@ "aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "dev": true + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" }, "are-we-there-yet": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.0.tgz", "integrity": "sha512-0GWpv50YSOcLXaN6/FAKY3vfRbllXWV2xvfA/oKJF8pzFhWXPV+yjhJXDBbjscDYowv7Yw1A3uigpzn5iEGTyw==", - "dev": true, + "devOptional": true, "requires": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" @@ -23166,8 +23412,7 @@ "chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" }, "chrome-trace-event": { "version": "1.0.3", @@ -23190,7 +23435,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true + "devOptional": true }, "cli-boxes": { "version": "2.2.1", @@ -23310,13 +23555,12 @@ "color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" }, "colorette": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", - "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==" + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", + "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==" }, "colors": { "version": "1.0.3", @@ -23345,8 +23589,7 @@ "commander": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/commander/-/commander-9.3.0.tgz", - "integrity": "sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw==", - "dev": true + "integrity": "sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw==" }, "common-ancestor-path": { "version": "1.0.1", @@ -23456,8 +23699,7 @@ "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" }, "content-disposition": { "version": "0.5.4", @@ -23873,6 +24115,11 @@ "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", "dev": true }, + "detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==" + }, "dezalgo": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", @@ -23973,9 +24220,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "electron-to-chromium": { - "version": "1.4.160", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.160.tgz", - "integrity": "sha512-O1Z12YfyeX2LXYO7MdHIPazGXzLzQnr1ADW55U2ARQsJBPgfpJz3u+g3Mo2l1wSyfOCdiGqaX9qtV4XKZ0HNRA==" + "version": "1.4.161", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.161.tgz", + "integrity": "sha512-sTjBRhqh6wFodzZtc5Iu8/R95OkwaPNn7tj/TaDU5nu/5EFiQDtADGAXdR4tJcTEHlYfJpHqigzJqHvPgehP8A==" }, "elliptic": { "version": "6.5.4", @@ -24103,7 +24350,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true + "devOptional": true }, "envinfo": { "version": "7.8.1", @@ -24114,7 +24361,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true + "devOptional": true }, "error-ex": { "version": "1.3.2", @@ -24347,6 +24594,11 @@ "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true }, + "esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==" + }, "espree": { "version": "9.3.2", "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", @@ -25000,7 +25252,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, "requires": { "minipass": "^3.0.0" } @@ -25039,7 +25290,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "dev": true, + "devOptional": true, "requires": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.3", @@ -25071,6 +25322,11 @@ "has-symbols": "^1.0.3" } }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==" + }, "get-pkg-repo": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz", @@ -25142,6 +25398,11 @@ "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true }, + "getopts": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/getopts/-/getopts-2.3.0.tgz", + "integrity": "sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA==" + }, "git-raw-commits": { "version": "2.0.11", "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz", @@ -25490,8 +25751,7 @@ "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" }, "has-yarn": { "version": "2.1.0", @@ -25606,7 +25866,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "dev": true + "devOptional": true }, "http-errors": { "version": "2.0.0", @@ -25631,7 +25891,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, + "devOptional": true, "requires": { "@tootallnate/once": "1", "agent-base": "6", @@ -25657,7 +25917,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "dev": true, + "devOptional": true, "requires": { "ms": "^2.0.0" } @@ -25723,19 +25983,19 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true + "devOptional": true }, "indent-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true + "devOptional": true }, "infer-owner": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true + "devOptional": true }, "inflation": { "version": "2.0.0", @@ -25838,9 +26098,9 @@ } }, "interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==" + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==" }, "invariant": { "version": "2.2.4", @@ -25972,7 +26232,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "dev": true + "devOptional": true }, "is-npm": { "version": "5.0.0", @@ -26419,6 +26679,34 @@ "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true }, + "knex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/knex/-/knex-2.1.0.tgz", + "integrity": "sha512-vVsnD6UJdSJy55TvCXfFF9syfwyXNxfE9mvr2hJL/4Obciy2EPGoqjDpgRSlMruHuPWDOeYAG25nyrGvU+jJog==", + "requires": { + "colorette": "2.0.16", + "commander": "^9.1.0", + "debug": "4.3.4", + "escalade": "^3.1.1", + "esm": "^3.2.25", + "get-package-type": "^0.1.0", + "getopts": "2.3.0", + "interpret": "^2.2.0", + "lodash": "^4.17.21", + "pg-connection-string": "2.5.0", + "rechoir": "^0.8.0", + "resolve-from": "^5.0.0", + "tarn": "^3.0.2", + "tildify": "2.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + } + } + }, "koa": { "version": "2.13.4", "resolved": "https://registry.npmjs.org/koa/-/koa-2.13.4.tgz", @@ -27232,7 +27520,7 @@ "version": "9.1.0", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", - "dev": true, + "devOptional": true, "requires": { "agentkeepalive": "^4.1.3", "cacache": "^15.2.0", @@ -27256,7 +27544,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", - "dev": true, + "devOptional": true, "requires": { "@gar/promisify": "^1.0.1", "semver": "^7.3.5" @@ -27266,7 +27554,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", - "dev": true, + "devOptional": true, "requires": { "mkdirp": "^1.0.4", "rimraf": "^3.0.2" @@ -27276,7 +27564,7 @@ "version": "15.3.0", "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", - "dev": true, + "devOptional": true, "requires": { "@npmcli/fs": "^1.0.0", "@npmcli/move-file": "^1.0.1", @@ -27302,7 +27590,7 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, + "devOptional": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -27316,7 +27604,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, + "devOptional": true, "requires": { "yallist": "^4.0.0" } @@ -27653,7 +27941,6 @@ "version": "3.1.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", - "dev": true, "requires": { "yallist": "^4.0.0" } @@ -27662,7 +27949,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "dev": true, + "devOptional": true, "requires": { "minipass": "^3.0.0" } @@ -27671,7 +27958,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", - "dev": true, + "devOptional": true, "requires": { "encoding": "^0.1.12", "minipass": "^3.1.0", @@ -27683,7 +27970,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "dev": true, + "devOptional": true, "requires": { "minipass": "^3.0.0" } @@ -27702,7 +27989,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "dev": true, + "devOptional": true, "requires": { "minipass": "^3.0.0" } @@ -27711,7 +27998,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "dev": true, + "devOptional": true, "requires": { "minipass": "^3.0.0" } @@ -27720,7 +28007,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, "requires": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -27729,8 +28015,7 @@ "mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" }, "mkdirp-infer-owner": { "version": "2.0.0", @@ -28236,6 +28521,11 @@ } } }, + "node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==" + }, "node-fetch": { "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", @@ -28269,7 +28559,7 @@ "version": "8.4.1", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", - "dev": true, + "devOptional": true, "requires": { "env-paths": "^2.2.0", "glob": "^7.1.4", @@ -28287,7 +28577,7 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, + "devOptional": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -28308,7 +28598,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "dev": true, "requires": { "abbrev": "1" } @@ -28656,7 +28945,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "dev": true, + "devOptional": true, "requires": { "are-we-there-yet": "^3.0.0", "console-control-strings": "^1.1.0", @@ -28822,7 +29111,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, + "devOptional": true, "requires": { "aggregate-error": "^3.0.0" } @@ -29252,6 +29541,11 @@ "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" }, + "pg-connection-string": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", + "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" + }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -29398,13 +29692,13 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "dev": true + "devOptional": true }, "promise-retry": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dev": true, + "devOptional": true, "requires": { "err-code": "^2.0.2", "retry": "^0.12.0" @@ -30034,11 +30328,11 @@ } }, "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", "requires": { - "resolve": "^1.1.6" + "resolve": "^1.20.0" } }, "redent": { @@ -30253,7 +30547,7 @@ "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "dev": true + "devOptional": true }, "reusify": { "version": "1.0.4", @@ -30494,8 +30788,7 @@ "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, "setprototypeof": { "version": "1.2.0", @@ -30545,6 +30838,19 @@ "once": "^1.3.0", "path-is-absolute": "^1.0.0" } + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==" + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "requires": { + "resolve": "^1.1.6" + } } } }, @@ -30665,7 +30971,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", - "dev": true, + "devOptional": true, "requires": { "agent-base": "^6.0.2", "debug": "^4.3.3", @@ -30770,6 +31076,17 @@ "readable-stream": "^3.0.0" } }, + "sqlite3": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.0.8.tgz", + "integrity": "sha512-f2ACsbSyb2D1qFFcqIXPfFscLtPVOWJr5GmUzYxf4W+0qelu5MWrR+FAQE1d5IUArEltBrzSDxDORG8P/IkqyQ==", + "requires": { + "@mapbox/node-pre-gyp": "^1.0.0", + "node-addon-api": "^4.2.0", + "node-gyp": "8.x", + "tar": "^6.1.11" + } + }, "sqwish": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/sqwish/-/sqwish-0.2.2.tgz", @@ -30779,7 +31096,7 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", - "dev": true, + "devOptional": true, "requires": { "minipass": "^3.1.1" } @@ -30958,7 +31275,6 @@ "version": "6.1.11", "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", - "dev": true, "requires": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -30992,6 +31308,11 @@ } } }, + "tarn": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.2.tgz", + "integrity": "sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==" + }, "temp-dir": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", @@ -31115,6 +31436,11 @@ "readable-stream": "3" } }, + "tildify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz", + "integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==" + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -31350,7 +31676,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "dev": true, + "devOptional": true, "requires": { "unique-slug": "^2.0.0" } @@ -31359,7 +31685,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", - "dev": true, + "devOptional": true, "requires": { "imurmurhash": "^0.1.4" } @@ -31649,11 +31975,6 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" }, - "interpret": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", - "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==" - }, "rechoir": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", @@ -31701,7 +32022,6 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, "requires": { "string-width": "^1.0.2 || 2 || 3 || 4" } diff --git a/packages/adapter-commons/src/service.ts b/packages/adapter-commons/src/service.ts index ce0d2059e1..fb5070fbaa 100644 --- a/packages/adapter-commons/src/service.ts +++ b/packages/adapter-commons/src/service.ts @@ -235,7 +235,7 @@ export abstract class AdapterBase< throw new MethodNotAllowed('Can not patch multiple entries') } - const query = await this.sanitizeQuery(params) + const { $limit, ...query } = await this.sanitizeQuery(params) const payload = await this.sanitizeData(data, params) return this.$patch(id, payload, { @@ -265,7 +265,7 @@ export abstract class AdapterBase< throw new MethodNotAllowed('Can not remove multiple entries') } - const query = await this.sanitizeQuery(params) + const { $limit, ...query } = await this.sanitizeQuery(params) return this.$remove(id, { ...params, diff --git a/packages/authentication-oauth/src/index.ts b/packages/authentication-oauth/src/index.ts index de15449b40..b72dd322be 100644 --- a/packages/authentication-oauth/src/index.ts +++ b/packages/authentication-oauth/src/index.ts @@ -42,18 +42,14 @@ export const setup = (options: OauthSetupSettings) => (app: Application) => { } } - const grant = defaultsDeep( - {}, - omit(oauth, ['redirect', 'origins']), - { - defaults: { - prefix: '/oauth', - origin: `${protocol}://${host}`, - transport: 'session', - response: ['tokens', 'raw', 'profile'] - } + const grant = defaultsDeep({}, omit(oauth, ['redirect', 'origins']), { + defaults: { + prefix: '/oauth', + origin: `${protocol}://${host}`, + transport: 'session', + response: ['tokens', 'raw', 'profile'] } - ) + }) const getUrl = (url: string) => { const { defaults } = grant diff --git a/packages/knex/CHANGELOG.md b/packages/knex/CHANGELOG.md new file mode 100644 index 0000000000..e4d87c4d45 --- /dev/null +++ b/packages/knex/CHANGELOG.md @@ -0,0 +1,4 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. diff --git a/packages/knex/LICENSE b/packages/knex/LICENSE new file mode 100644 index 0000000000..59604f46f3 --- /dev/null +++ b/packages/knex/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2022 Feathers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/packages/knex/README.md b/packages/knex/README.md new file mode 100644 index 0000000000..4e9adac6a5 --- /dev/null +++ b/packages/knex/README.md @@ -0,0 +1,22 @@ +# @feathersjs/knex + +[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI) +[![Download Status](https://img.shields.io/npm/dm/@feathersjs/mongodb.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/mongodb) + +> Feathers SQL service adapter using KnexJS + +## Installation + +``` +npm install @feathersjs/knex --save +``` + +## Documentation + +Refer to the [Feathers documentation](https://docs.feathersjs.com) for more details. + +## License + +Copyright (c) 2022 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors) + +Licensed under the [MIT license](LICENSE). diff --git a/packages/knex/package.json b/packages/knex/package.json new file mode 100644 index 0000000000..ace71f4a50 --- /dev/null +++ b/packages/knex/package.json @@ -0,0 +1,71 @@ +{ + "name": "@feathersjs/knex", + "description": "Feathers SQL service adapter using KnexJS", + "version": "5.0.0-pre.23", + "homepage": "https://feathersjs.com", + "main": "lib/", + "keywords": [ + "feathers", + "feathers-plugin" + ], + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/daffl" + }, + "repository": { + "type": "git", + "url": "git://github.com/feathersjs/feathers.git" + }, + "author": { + "name": "Feathers contributors", + "email": "hello@feathersjs.com", + "url": "https://feathersjs.com" + }, + "contributors": [], + "bugs": { + "url": "https://github.com/feathersjs/feathers/issues" + }, + "engines": { + "node": ">= 14" + }, + "files": [ + "CHANGELOG.md", + "LICENSE", + "README.md", + "src/**", + "lib/**", + "*.d.ts", + "*.js" + ], + "scripts": { + "compile": "shx rm -rf lib/ && tsc", + "test": "mocha --config ../../.mocharc.json --recursive test/**.test.ts test/**/*.test.ts" + }, + "directories": { + "lib": "lib" + }, + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@feathersjs/feathers": "^5.0.0-pre.23", + "@feathersjs/commons": "^5.0.0-pre.23", + "@feathersjs/errors": "^5.0.0-pre.23", + "@feathersjs/adapter-commons": "^5.0.0-pre.23" + }, + "peerDependencies": { + "knex": "^2.1.0" + }, + "devDependencies": { + "@feathersjs/adapter-tests": "^5.0.0-pre.23", + "@types/mocha": "^9.1.1", + "@types/node": "^17.0.40", + "mocha": "^10.0.0", + "sqlite3": "^5.0.8", + "shx": "^0.3.4", + "typescript": "^4.7.3", + "knex": "^2.1.0" + }, + "gitHead": "a60910bd730b88053ca6648337095f1ca1e3b39f" +} diff --git a/packages/knex/src/adapter.ts b/packages/knex/src/adapter.ts new file mode 100644 index 0000000000..b5de594a12 --- /dev/null +++ b/packages/knex/src/adapter.ts @@ -0,0 +1,314 @@ +import { Id, NullableId, Paginated, Query } from '@feathersjs/feathers' +import { _ } from '@feathersjs/commons' +import { AdapterBase, PaginationOptions, filterQuery } from '@feathersjs/adapter-commons' +import { NotFound } from '@feathersjs/errors' +import { Knex } from 'knex' + +import { errorHandler } from './error-handler' +import { KnexAdapterOptions, KnexAdapterParams } from './declarations' +const METHODS = { + $ne: 'whereNot', + $in: 'whereIn', + $nin: 'whereNotIn', + $or: 'orWhere', + $and: 'andWhere' +} + +const OPERATORS = { + $lt: '<', + $lte: '<=', + $gt: '>', + $gte: '>=', + $like: 'like', + $notlike: 'not like', + $ilike: 'ilike' +} + +export class KnexAdapter< + T, + D = Partial, + P extends KnexAdapterParams = KnexAdapterParams +> extends AdapterBase { + table: string + schema?: string + + constructor(options: KnexAdapterOptions) { + if (!options || !options.Model) { + throw new Error('You must provide a Model (the initialized knex object)') + } + + if (typeof options.name !== 'string') { + throw new Error('No table name specified.') + } + + super({ + id: 'id', + ...options, + filters: { + ...options.filters, + $and: (value: any) => value + }, + operators: [...(options.operators || []), '$like', '$notlike', '$ilike', '$and', '$or'] + }) + + this.table = options.name + this.schema = options.schema + } + + get Model() { + return this.options.Model + } + + get fullName() { + return this.schema ? `${this.schema}.${this.table}` : this.table + } + + db(params?: P) { + const { Model, table, schema } = this + + if (params && params.transaction && params.transaction.trx) { + const { trx } = params.transaction + // debug('ran %s with transaction %s', fullName, id) + return schema ? (trx.withSchema(schema).table(table) as Knex.QueryBuilder) : trx(table) + } + return schema ? (Model.withSchema(schema).table(table) as Knex.QueryBuilder) : Model(table) + } + + knexify(knexQuery: Knex.QueryBuilder, query: Query = {}, parentKey?: string): Knex.QueryBuilder { + const knexify = this.knexify.bind(this) + + return Object.keys(query || {}).reduce((currentQuery, key) => { + const value = query[key] + + if (_.isObject(value)) { + return knexify(currentQuery, value, key) + } + + const column = parentKey || key + const method = METHODS[key as keyof typeof METHODS] + + if (method) { + if (key === '$or' || key === '$and') { + // This will create a nested query + currentQuery.where(function (this: any) { + for (const condition of value) { + this[method](function (this: Knex.QueryBuilder) { + knexify(this, condition) + }) + } + }) + + return currentQuery + } + + return (currentQuery as any)[method](column, value) + } + + const operator = OPERATORS[key as keyof typeof OPERATORS] || '=' + + return operator === '=' + ? currentQuery.where(column, value) + : currentQuery.where(column, operator, value) + }, knexQuery) + } + + createQuery(params: P) { + const { table, id } = this + const { filters, query } = this.filterQuery(params) + const builder = this.db(params) + + // $select uses a specific find syntax, so it has to come first. + if (filters.$select) { + // always select the id field, but make sure we only select it once + builder.select(...new Set([...filters.$select, `${table}.${id}`])) + } else { + builder.select(`${table}.*`) + } + + // build up the knex query out of the query params, include $and and $or filters + this.knexify(builder, { + ...query, + ..._.pick(filters, '$and', '$or') + }) + + // Handle $sort + if (filters.$sort) { + return Object.keys(filters.$sort).reduce( + (currentQuery, key) => currentQuery.orderBy(key, filters.$sort[key] === 1 ? 'asc' : 'desc'), + builder + ) + } + + return builder + } + + filterQuery(params: P) { + const options = this.getOptions(params) + const { filters, query } = filterQuery(params?.query || {}, options) + + return { filters, query, paginate: options.paginate } + } + + async $find(params?: P & { paginate?: PaginationOptions }): Promise> + async $find(params?: P & { paginate: false }): Promise + async $find(params?: P): Promise | T[]> + async $find(params: P = {} as P): Promise | T[]> { + const { filters, paginate } = this.filterQuery(params) + const builder = params.knex ? params.knex.clone() : this.createQuery(params) + const countBuilder = builder.clone().count(`${this.table}.${this.id} as total`) + + // Handle $limit + if (filters.$limit) { + builder.limit(filters.$limit) + } + + // Handle $skip + if (filters.$skip) { + builder.offset(filters.$skip) + } + + // provide default sorting if its not set + if (!filters.$sort) { + builder.orderBy(`${this.table}.${this.id}`, 'asc') + } + + const data = filters.$limit === 0 ? [] : await builder + + if (paginate && paginate.default) { + return { + total: await countBuilder.then((count) => (count[0] ? count[0].total : 0)), + limit: filters.$limit, + skip: filters.$skip || 0, + data + } + } + + return data + } + + async _findOrGet(id: NullableId, params?: P) { + const findParams = { + ...params, + paginate: false, + query: { + ...params?.query, + ...(id !== null ? { [`${this.table}.${this.id}`]: id } : {}) + } + } + + return this.$find(findParams as any) as any as Promise + } + + async $get(id: Id, params: P = {} as P): Promise { + const data = await this._findOrGet(id, params) + + if (data.length !== 1) { + throw new NotFound(`No record found for id '${id}'`) + } + + return data[0] + } + + async $create(data: Partial, params?: P): Promise + async $create(data: Partial[], params?: P): Promise + async $create(data: Partial | Partial[], _params?: P): Promise + async $create(_data: Partial | Partial[], params: P = {} as P): Promise { + const data = _data as any + + if (Array.isArray(data)) { + return Promise.all(data.map((current) => this.$create(current, params))) + } + + const client = this.db(params).client.config.client + const returning = client === 'pg' || client === 'oracledb' || client === 'mssql' ? [this.id] : [] + const rows: any = await this.db(params).insert(data, returning).catch(errorHandler) + const id = data[this.id] || rows[0][this.id] || rows[0] + + if (!id) { + return rows as T[] + } + + return this.$get(id, params) + } + + async $patch(id: null, data: Partial, params?: P): Promise + async $patch(id: Id, data: Partial, params?: P): Promise + async $patch(id: NullableId, data: Partial, _params?: P): Promise + async $patch(id: NullableId, raw: Partial, params: P = {} as P): Promise { + const data = _.omit(raw, this.id) + const results = await this._findOrGet(id, { + ...params, + query: { + ...params?.query, + $select: [`${this.table}.${this.id}`] + } + }) + const idList = results.map((current: any) => current[this.id]) + const updateParams = { + ...params, + query: { + [`${this.table}.${this.id}`]: { $in: idList }, + ...(params?.query?.$select ? { $select: params?.query?.$select } : {}) + } + } + const builder = this.createQuery(updateParams) + + await builder.update(data) + + const items = await this._findOrGet(null, updateParams) + + if (id !== null) { + if (items.length === 1) { + return items[0] + } else { + throw new NotFound(`No record found for id '${id}'`) + } + } + + return items + } + + async $update(id: Id, _data: D, params: P = {} as P): Promise { + const data = _.omit(_data, this.id) + const oldData = await this.$get(id, params) + const newObject = Object.keys(oldData).reduce((result: any, key) => { + if (key !== this.id) { + // We don't want the id field to be changed + result[key] = data[key] === undefined ? null : data[key] + } + + return result + }, {}) + + await this.db(params).update(newObject, '*').where(this.id, id) + + return this.$get(id, params) + } + + async $remove(id: null, params?: P): Promise + async $remove(id: Id, params?: P): Promise + async $remove(id: NullableId, _params?: P): Promise + async $remove(id: NullableId, params: P = {} as P): Promise { + const items = await this._findOrGet(id, params) + const { query } = this.filterQuery(params) + const q = this.db(params) + const idList = items.map((current: any) => current[this.id]) + + query[this.id] = { $in: idList } + + // build up the knex query out of the query params + this.knexify(q, query) + + await q.del().catch(errorHandler) + + if (id !== null) { + if (items.length === 1) { + return items[0] + } + + throw new NotFound(`No record found for id '${id}'`) + } + + return items + } +} diff --git a/packages/knex/src/declarations.ts b/packages/knex/src/declarations.ts new file mode 100644 index 0000000000..4e30ba6a0a --- /dev/null +++ b/packages/knex/src/declarations.ts @@ -0,0 +1,23 @@ +import { Knex } from 'knex' +import { AdapterServiceOptions, AdapterParams, AdapterQuery } from '@feathersjs/adapter-commons' + +export interface KnexAdapterOptions extends AdapterServiceOptions { + Model: Knex + name: string + schema?: string +} + +export interface KnexAdapterTransaction { + starting: boolean + parent?: KnexAdapterTransaction + committed?: any + resolve?: any + trx?: Knex.Transaction + id?: number + promise?: Promise +} + +export interface KnexAdapterParams extends AdapterParams> { + knex?: Knex.QueryBuilder + transaction?: KnexAdapterTransaction +} diff --git a/packages/knex/src/error-handler.ts b/packages/knex/src/error-handler.ts new file mode 100644 index 0000000000..62662a7702 --- /dev/null +++ b/packages/knex/src/error-handler.ts @@ -0,0 +1,95 @@ +import { errors } from '@feathersjs/errors' + +export const ERROR = Symbol('@feathersjs/knex/error') + +export function errorHandler(error: any) { + const { message } = error + let feathersError = error + + if (error.sqlState && error.sqlState.length) { + // remove SQLSTATE marker (#) and pad/truncate SQLSTATE to 5 chars + const sqlState = ('00000' + error.sqlState.replace('#', '')).slice(-5) + + switch (sqlState.slice(0, 2)) { + case '02': + feathersError = new errors.NotFound(message) + break + case '28': + feathersError = new errors.Forbidden(message) + break + case '08': + case '0A': + case '0K': + feathersError = new errors.Unavailable(message) + break + case '20': + case '21': + case '22': + case '23': + case '24': + case '25': + case '40': + case '42': + case '70': + feathersError = new errors.BadRequest(message) + break + default: + feathersError = new errors.GeneralError(message) + } + } else if (error.code === 'SQLITE_ERROR') { + // NOTE (EK): Error codes taken from + // https://www.sqlite.org/c3ref/c_abort.html + switch (error.errno) { + case 1: + case 8: + case 18: + case 19: + case 20: + feathersError = new errors.BadRequest(message) + break + case 2: + feathersError = new errors.Unavailable(message) + break + case 3: + case 23: + feathersError = new errors.Forbidden(message) + break + case 12: + feathersError = new errors.NotFound(message) + break + default: + feathersError = new errors.GeneralError(message) + break + } + } else if (typeof error.code === 'string' && error.severity && error.routine) { + // NOTE: Error codes taken from + // https://www.postgresql.org/docs/9.6/static/errcodes-appendix.html + // Omit query information + const messages = error.message.split('-') + error.message = messages[messages.length - 1] + + switch (error.code.slice(0, 2)) { + case '22': + case '23': + feathersError = new errors.BadRequest(message) + break + case '28': + feathersError = new errors.Forbidden(message) + break + case '3D': + case '3F': + case '42': + feathersError = new errors.Unprocessable(message) + break + default: + feathersError = new errors.GeneralError(message) + break + } + } else if (!(error instanceof errors.FeathersError)) { + feathersError = new errors.GeneralError(message) + } + + feathersError[ERROR] = error + + throw feathersError +} diff --git a/packages/knex/src/hooks.ts b/packages/knex/src/hooks.ts new file mode 100644 index 0000000000..1ef169570c --- /dev/null +++ b/packages/knex/src/hooks.ts @@ -0,0 +1,101 @@ +import { createDebug } from '@feathersjs/commons' +import { HookContext } from '@feathersjs/feathers' +import { Knex } from 'knex' +import { KnexAdapterTransaction } from './declarations' + +const debug = createDebug('feathers-knex-transaction') + +const ROLLBACK = { rollback: true } + +export const getKnex = (context: HookContext): Knex => { + const knex = context.service.Model + + return knex && typeof knex.transaction === 'function' ? knex : undefined +} + +export const start = + () => + async (context: HookContext): Promise => { + const { transaction } = context.params + const parent = transaction + const knex: Knex = transaction ? transaction.trx : getKnex(context) + + if (!knex) { + return + } + + return new Promise((resolve, reject) => { + const transaction: KnexAdapterTransaction = { + starting: true + } + + if (parent) { + transaction.parent = parent + transaction.committed = parent.committed + } else { + transaction.committed = new Promise((resolve) => { + transaction.resolve = resolve + }) + } + + transaction.starting = true + transaction.promise = knex + .transaction((trx) => { + transaction.trx = trx + transaction.id = Date.now() + + context.params = { ...context.params, transaction } + + debug('started a new transaction %s', transaction.id) + + resolve() + }) + .catch((error) => { + if (transaction.starting) { + reject(error) + } else if (error !== ROLLBACK) { + throw error + } + }) + }) + } + +export const end = () => (context: HookContext) => { + const { transaction } = context.params + + if (!transaction) { + return + } + + const { trx, id, promise, parent } = transaction + + context.params = { ...context.params, transaction: parent } + transaction.starting = false + + return trx + .commit() + .then(() => promise) + .then(() => transaction.resolve && transaction.resolve(true)) + .then(() => debug('ended transaction %s', id)) + .then(() => context) +} + +export const rollback = () => (context: HookContext) => { + const { transaction } = context.params + + if (!transaction) { + return + } + + const { trx, id, promise, parent } = transaction + + context.params = { ...context.params, transaction: parent } + transaction.starting = false + + return trx + .rollback(ROLLBACK) + .then(() => promise) + .then(() => transaction.resolve && transaction.resolve(false)) + .then(() => debug('rolled back transaction %s', id)) + .then(() => context) +} diff --git a/packages/knex/src/index.ts b/packages/knex/src/index.ts new file mode 100644 index 0000000000..1fef087153 --- /dev/null +++ b/packages/knex/src/index.ts @@ -0,0 +1,47 @@ +import { PaginationOptions } from '@feathersjs/adapter-commons' +import { Paginated, ServiceMethods, Id, NullableId } from '@feathersjs/feathers' +import { KnexAdapter } from './adapter' +import { KnexAdapterParams } from './declarations' + +export * from './declarations' +export * from './adapter' +export * from './error-handler' +export * as transaction from './hooks' + +export class KnexService, P extends KnexAdapterParams = KnexAdapterParams> + extends KnexAdapter + implements ServiceMethods, D, P> +{ + async find(params?: P & { paginate?: PaginationOptions }): Promise> + async find(params?: P & { paginate: false }): Promise + async find(params?: P): Promise | T[]> + async find(params?: P): Promise | T[]> { + return this._find(params) as any + } + + async get(id: Id, params?: P): Promise { + return this._get(id, params) + } + + async create(data: Partial, params?: P): Promise + async create(data: Partial[], params?: P): Promise + async create(data: Partial | Partial[], params?: P): Promise { + return this._create(data, params) + } + + async update(id: Id, data: D, params?: P): Promise { + return this._update(id, data, params) + } + + async patch(id: Id, data: Partial, params?: P): Promise + async patch(id: null, data: Partial, params?: P): Promise + async patch(id: NullableId, data: Partial, params?: P): Promise { + return this._patch(id, data, params) + } + + async remove(id: Id, params?: P): Promise + async remove(id: null, params?: P): Promise + async remove(id: NullableId, params?: P): Promise { + return this._remove(id, params) + } +} diff --git a/packages/knex/test/connection.ts b/packages/knex/test/connection.ts new file mode 100644 index 0000000000..d635b77dbb --- /dev/null +++ b/packages/knex/test/connection.ts @@ -0,0 +1,32 @@ +export default (DB: string) => { + if (DB === 'mysql') { + return { + client: 'mysql', + connection: { + host: '127.0.0.1', + user: 'root', + password: '', + database: 'feathers_knex' + } + } + } + + if (DB === 'postgres') { + return { + client: 'postgresql', + connection: { + host: 'localhost', + database: 'sequelize', + user: 'postgres', + password: 'password' + } + } + } + + return { + client: 'sqlite3', + connection: { + filename: './db.sqlite' + } + } +} diff --git a/packages/knex/test/index.test.ts b/packages/knex/test/index.test.ts new file mode 100644 index 0000000000..62045197a3 --- /dev/null +++ b/packages/knex/test/index.test.ts @@ -0,0 +1,612 @@ +import knex, { Knex } from 'knex' +import assert from 'assert' +import { feathers, HookContext, Service } from '@feathersjs/feathers' +import adapterTests from '@feathersjs/adapter-tests' +import { errors } from '@feathersjs/errors' + +import connection from './connection' +import { KnexService, transaction } from '../src/index' + +const testSuite = adapterTests([ + '.options', + '.events', + '._get', + '._find', + '._create', + '._update', + '._patch', + '._remove', + '.$get', + '.$find', + '.$create', + '.$update', + '.$patch', + '.$remove', + '.get', + '.get + $select', + '.get + id + query', + '.get + NotFound', + '.get + id + query id', + '.find', + '.remove', + '.remove + $select', + '.remove + id + query', + '.remove + multi', + '.remove + multi no pagination', + '.remove + id + query id', + '.update', + '.update + $select', + '.update + id + query', + '.update + NotFound', + '.update + query + NotFound', + '.update + id + query id', + '.patch', + '.patch + $select', + '.patch + id + query', + '.patch multiple', + '.patch multiple no pagination', + '.patch multi query same', + '.patch multi query changed', + '.patch + NotFound', + '.patch + query + NotFound', + '.patch + id + query id', + '.create', + '.create + $select', + '.create multi', + 'internal .find', + 'internal .get', + 'internal .create', + 'internal .update', + 'internal .patch', + 'internal .remove', + '.find + equal', + '.find + equal multiple', + '.find + $sort', + '.find + $sort + string', + '.find + $limit', + '.find + $limit 0', + '.find + $skip', + '.find + $select', + '.find + $or', + '.find + $in', + '.find + $nin', + '.find + $lt', + '.find + $lte', + '.find + $gt', + '.find + $gte', + '.find + $ne', + '.find + $gt + $lt + $sort', + '.find + $or nested + $sort', + 'params.adapter + paginate', + 'params.adapter + multi', + '.find + paginate', + '.find + paginate + query', + '.find + paginate + $limit + $skip', + '.find + paginate + $limit 0', + '.find + paginate + params' +]) + +const TYPE = process.env.DB || 'sqlite' +const db = knex(connection(TYPE) as any) + +// Create a public database to mimic a "schema" +const schemaName = 'public' + +function clean() { + return Promise.all([ + db.schema.dropTableIfExists(people.fullName).then(() => { + return db.schema.createTable(people.fullName, (table) => { + table.increments('id') + table.string('name').notNullable() + table.integer('age') + table.integer('time') + table.boolean('created') + return table + }) + }), + db.schema.dropTableIfExists(peopleId.fullName).then(() => { + return db.schema.createTable(peopleId.fullName, (table) => { + table.increments('customid') + table.string('name') + table.integer('age') + table.integer('time') + table.boolean('created') + return table + }) + }), + db.schema.dropTableIfExists(users.fullName).then(() => { + return db.schema.createTable(users.fullName, (table) => { + table.increments('id') + table.string('name') + table.integer('age') + table.integer('time') + table.boolean('created') + return table + }) + }) + ]) +} + +type Person = { + id: number + name: string + age: number | null + time: string + create: boolean +} + +type ServiceTypes = { + people: KnexService + 'people-customid': KnexService + users: KnexService +} + +const people = new KnexService({ + Model: db, + name: 'people', + events: ['testing'] +}) + +const peopleId = new KnexService({ + Model: db, + id: 'customid', + name: 'people-customid', + events: ['testing'] +}) + +const users = new KnexService({ + Model: db, + name: 'users', + events: ['testing'] +}) + +describe('Feathers Knex Service', () => { + const app = feathers() + .hooks({ + before: [transaction.start()], + after: [transaction.end()], + error: [transaction.rollback()] + }) + .use('people', people) + .use('people-customid', peopleId) + .use('users', users) + const peopleService = app.service('people') + + before(() => { + if (TYPE === 'sqlite') { + // Attach the public database to mimic a "schema" + db.schema.raw(`attach database '${schemaName}.sqlite' as ${schemaName}`) + } + }) + before(clean) + after(clean) + + describe('$like method', () => { + let charlie: Person + + beforeEach(async () => { + charlie = await peopleService.create({ + name: 'Charlie Brown', + age: 10 + }) + }) + + afterEach(() => peopleService.remove(charlie.id)) + + it('$like in query', async () => { + const data = await peopleService.find({ + paginate: false, + query: { name: { $like: '%lie%' } } + }) + + assert.strictEqual(data[0].name, 'Charlie Brown') + }) + }) + + describe('$notlike method', () => { + let hasMatch: Person + let hasNoMatch: Person + + beforeEach(async () => { + hasMatch = await peopleService.create({ + name: 'XYZabcZYX' + }) + hasNoMatch = await peopleService.create({ + name: 'XYZZYX' + }) + }) + + afterEach(() => { + peopleService.remove(hasMatch.id) + peopleService.remove(hasNoMatch.id) + }) + + it('$notlike in query', async () => { + const data = await peopleService.find({ + paginate: false, + query: { name: { $notlike: '%abc%' } } + }) + + assert.strictEqual(data.length, 1) + assert.strictEqual(data[0].name, 'XYZZYX') + }) + }) + + describe('adapter specifics', () => { + let daves: Person[] + + beforeEach(async () => { + daves = await Promise.all([ + peopleService.create({ + name: 'Ageless', + age: null + }), + peopleService.create({ + name: 'Dave', + age: 32 + }), + peopleService.create({ + name: 'Dada', + age: 1 + }) + ]) + }) + + afterEach(async () => { + try { + await peopleService.remove(daves[0].id) + await peopleService.remove(daves[1].id) + await peopleService.remove(daves[2].id) + } catch (error: unknown) {} + }) + + it('$or works properly (#120)', async () => { + const data = await peopleService.find({ + paginate: false, + query: { + name: 'Dave', + $or: [ + { + age: 1 + }, + { + age: 32 + } + ] + } + }) + + assert.strictEqual(data.length, 1) + assert.strictEqual(data[0].name, 'Dave') + assert.strictEqual(data[0].age, 32) + }) + + it('$and works properly', async () => { + const data = await peopleService.find({ + paginate: false, + query: { + $and: [ + { + $or: [{ name: 'Dave' }, { name: 'Dada' }] + }, + { + age: { $lt: 23 } + } + ] + } + }) + + assert.strictEqual(data.length, 1) + assert.strictEqual(data[0].name, 'Dada') + assert.strictEqual(data[0].age, 1) + }) + + it('where conditions support NULL values properly', async () => { + const data = await peopleService.find({ + paginate: false, + query: { + age: null + } + }) + + assert.strictEqual(data.length, 1) + assert.strictEqual(data[0].name, 'Ageless') + assert.strictEqual(data[0].age, null) + }) + + it('where conditions support NOT NULL case properly', async () => { + const data = await peopleService.find({ + paginate: false, + query: { + age: { $ne: null } + } + }) + + assert.strictEqual(data.length, 2) + assert.notStrictEqual(data[0].name, 'Ageless') + assert.notStrictEqual(data[0].age, null) + assert.notStrictEqual(data[1].name, 'Ageless') + assert.notStrictEqual(data[1].age, null) + }) + + it('where conditions support NULL values within AND conditions', async () => { + const data = await peopleService.find({ + paginate: false, + query: { + age: null, + name: 'Ageless' + } + }) + + assert.strictEqual(data.length, 1) + assert.strictEqual(data[0].name, 'Ageless') + assert.strictEqual(data[0].age, null) + }) + + it('where conditions support NULL values within OR conditions', async () => { + const data = await peopleService.find({ + paginate: false, + query: { + $or: [ + { + age: null + }, + { + name: 'Dada' + } + ] + } + }) + + assert.strictEqual(data.length, 2) + assert.notStrictEqual(data[0].name, 'Dave') + assert.notStrictEqual(data[0].age, 32) + assert.notStrictEqual(data[1].name, 'Dave') + assert.notStrictEqual(data[1].age, 32) + }) + + it('attaches the SQL error', async () => { + await assert.rejects(() => peopleService.create({}), { + name: 'GeneralError' + }) + }) + }) + + describe('hooks', () => { + afterEach(async () => { + await db('people').truncate() + }) + + it('does reject on problem with commit', async () => { + const app = feathers() + + app.hooks({ + before: transaction.start(), + after: [ + (context: HookContext) => { + const client = context.params.transaction.trx.client + const query = client.query + + client.query = (conn: any, sql: any) => { + let result = query.call(client, conn, sql) + + if (sql === 'COMMIT;') { + result = result.then(() => { + throw new TypeError('Deliberate') + }) + } + + return result + } + }, + transaction.end() + ], + error: transaction.rollback() + }) + + app.use('/people', people) + + await assert.rejects(() => app.service('/people').create({ name: 'Foo' }), { + message: 'Deliberate' + }) + }) + + it('does commit, rollback, nesting', async () => { + const app = feathers<{ + people: typeof people + test: Pick & { Model: Knex } + }>() + + app.hooks({ + before: transaction.start(), + after: transaction.end(), + error: transaction.rollback() + }) + + app.use('people', people) + + app.use('test', { + Model: db, + create: async (data: any, params) => { + const created = await app.service('people').create({ name: 'Foo' }, { ...params }) + + if (data.throw) { + throw new TypeError('Deliberate') + } + + return created + } + }) + + await assert.rejects(() => app.service('test').create({ throw: true }), { + message: 'Deliberate' + }) + + assert.strictEqual((await app.service('people').find({ paginate: false })).length, 0) + + await app.service('test').create({}) + + assert.strictEqual((await app.service('people').find({ paginate: false })).length, 1) + }) + + it('does use savepoints for nested calls', async () => { + const app = feathers<{ + people: typeof people + success: Pick & { Model: Knex } + fail: Pick & { Model: Knex } + test: Pick & { Model: Knex } + }>() + + app.hooks({ + before: transaction.start(), + after: transaction.end(), + error: transaction.rollback() + }) + + app.use('people', people) + + app.use('success', { + Model: db, + create: async (_data, params) => { + return app.service('people').create({ name: 'Success' }, { ...params }) + } + }) + + app.use('fail', { + Model: db, + create: async (_data, params) => { + await app.service('people').create({ name: 'Fail' }, { ...params }) + throw new TypeError('Deliberate') + } + }) + + app.use('test', { + Model: db, + create: async (_data, params) => { + await app.service('success').create({}, { ...params }) + await app + .service('fail') + .create({}, { ...params }) + // eslint-disable-next-line @typescript-eslint/no-empty-function + .catch(() => {}) + return [] + } + }) + + await app.service('test').create({}) + + const created = await app.service('people').find({ paginate: false }) + + assert.strictEqual(created.length, 1) + assert.ok(created[0].name) + }) + + it('allows waiting for transaction to complete', async () => { + const app = feathers<{ + people: typeof people + test: Pick & { Model: Knex } + }>() + + let seq: string[] = [] + + app.hooks({ + before: [ + transaction.start(), + (context: HookContext) => { + seq.push(`${context.path}: waiting for trx to be committed`) + context.params.transaction.committed.then((success: any) => { + seq.push(`${context.path}: committed ${success}`) + }) + }, + async (context: HookContext) => { + seq.push(`${context.path}: another hook`) + } + ], + after: [ + transaction.end(), + (context: HookContext) => { + seq.push(`${context.path}: trx ended`) + } + ], + error: [ + transaction.rollback(), + (context: HookContext) => { + seq.push(`${context.path}: trx rolled back`) + } + ] + }) + + app.use('people', people) + + app.use('test', { + Model: db, + create: async (data: any, params) => { + const peeps = await app.service('people').create({ name: 'Foo' }, { ...params }) + + if (data.throw) { + throw new TypeError('Deliberate') + } + return peeps + } + }) + + assert.deepStrictEqual(seq, []) + + await assert.rejects(() => app.service('test').create({ throw: true }), { + message: 'Deliberate' + }) + + assert.deepStrictEqual(seq, [ + 'test: waiting for trx to be committed', + 'test: another hook', + 'people: waiting for trx to be committed', + 'people: another hook', + 'people: trx ended', + 'test: committed false', + 'people: committed false', + 'test: trx rolled back' + ]) + + seq = [] + + assert.strictEqual((await app.service('people').find({ paginate: false })).length, 0) + + assert.deepStrictEqual(seq, [ + 'people: waiting for trx to be committed', + 'people: another hook', + 'people: committed true', + 'people: trx ended' + ]) + + seq = [] + + await app.service('test').create({}) + + assert.deepStrictEqual(seq, [ + 'test: waiting for trx to be committed', + 'test: another hook', + 'people: waiting for trx to be committed', + 'people: another hook', + 'people: trx ended', + 'test: committed true', + 'people: committed true', + 'test: trx ended' + ]) + + seq = [] + + assert.strictEqual((await app.service('people').find({ paginate: false })).length, 1) + + assert.deepStrictEqual(seq, [ + 'people: waiting for trx to be committed', + 'people: another hook', + 'people: committed true', + 'people: trx ended' + ]) + }) + }) + + testSuite(app, errors, 'users') + testSuite(app, errors, 'people') + testSuite(app, errors, 'people-customid', 'customid') +}) diff --git a/packages/knex/test/overrides.test.ts b/packages/knex/test/overrides.test.ts new file mode 100644 index 0000000000..076dc3c6b4 --- /dev/null +++ b/packages/knex/test/overrides.test.ts @@ -0,0 +1,125 @@ +import knex from 'knex' +import assert from 'assert' +import { feathers, Paginated } from '@feathersjs/feathers' +import { KnexAdapterParams, KnexService, transaction } from '../src' +import { PaginationOptions } from '@feathersjs/adapter-commons' + +// const { transaction } = service.hooks + +const db = knex({ + client: 'sqlite3', + connection: { + filename: './db.sqlite' + } +}) + +const schemaName = 'overrides' + +knex({ + client: 'sqlite3', + connection: { + filename: `./${schemaName}.sqlite` + } +}) + +type Animal = { + id: number + ancestor_id: number + ancestor_name: string + name: string +} + +/** + * Override the _find() method to manipulate the knex query, and + * introduce ambiguity by the table to itself. + */ +class AnimalService extends KnexService { + async $find(params?: P & { paginate?: PaginationOptions }): Promise> + async $find(params?: P & { paginate: false }): Promise + async $find(params?: P): Promise | T[]> + async $find(params: P = {} as P): Promise | T[]> { + const knexQuery = this.createQuery(params) + knexQuery + .select('ancestors.name as ancestor_name') + .leftJoin('animals as ancestors', 'ancestors.id', '=', 'animals.ancestor_id') + params.knex = knexQuery + return super.$find(params) + } +} + +const animals = new AnimalService({ + Model: db, + name: 'animals', + events: ['testing'] +}) + +function clean() { + return db.schema.dropTableIfExists(animals.fullName).then(() => { + return db.schema.createTable(animals.fullName, (table) => { + table.increments('id') + table.integer('ancestor_id') + table.string('name').notNullable() + return table + }) + }) +} + +describe('Feathers Knex Overridden Method With Self-Join', () => { + let ancestor: Animal + let animal: Animal + + const app = feathers<{ animals: AnimalService }>() + .hooks({ + before: [transaction.start()], + after: [transaction.end()], + error: [transaction.rollback()] + }) + .use('animals', animals) + const animalService = app.service('animals') + + before(() => { + return db.schema.raw(`attach database '${schemaName}.sqlite' as ${schemaName}`) + }) + before(clean) + after(clean) + + beforeEach(async () => { + ancestor = await animalService.create({ + name: 'Ape' + }) + animal = await animalService.create({ + ancestor_id: ancestor.id, + name: 'Human' + }) + }) + + it('finds properly', async () => { + const foundAnimals = await animalService.find({ + paginate: false, + query: { + $limit: 1, + ancestor_name: 'Ape' + } + }) + assert.strictEqual(foundAnimals[0].id, animal.id) + assert.strictEqual(foundAnimals[0].name, 'Human') + assert.strictEqual(foundAnimals[0].ancestor_name, 'Ape') + }) + + /** + * Previously, any query modified to include joins with ambiguous primary keys + * would yield an ambiguous column errors: + * BadRequest: select `animals`.* + * from `animals` + * left join `animals` as `ancestors` on `ancestors`.`id` = `animals`.`ancestor_id` + * where `id` in (2) - SQLITE_ERROR: ambiguous column name: id + * + * The fix involves explicitly specifying the table to query in the _patch() method + */ + it('patches without ambiguous query', async () => { + const newName = 'Homo Sapiens' + const patchedAnimal = await animalService.patch(animal.id, { name: newName }) + + assert.strictEqual(patchedAnimal.name, newName) + }) +}) diff --git a/packages/knex/tsconfig.json b/packages/knex/tsconfig.json new file mode 100644 index 0000000000..316fd41336 --- /dev/null +++ b/packages/knex/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig", + "include": [ + "src/**/*.ts" + ], + "compilerOptions": { + "outDir": "lib" + } +} diff --git a/packages/mongodb/src/adapter.ts b/packages/mongodb/src/adapter.ts index 35e6bd30fb..263d06866e 100644 --- a/packages/mongodb/src/adapter.ts +++ b/packages/mongodb/src/adapter.ts @@ -237,7 +237,7 @@ export class MongoDbAdapter< const model = await Promise.resolve(Model) const { query, - filters: { $select, $limit } + filters: { $select } } = this.filterQuery(id, params) const updateOptions = { ...params.mongodb } const modifier = Object.keys(data).reduce((current, key) => { @@ -268,7 +268,6 @@ export class MongoDbAdapter< ...params, paginate: false, query: { - ...($limit === 0 ? { $limit: 0 } : {}), [this.id]: { $in: idList }, $select } @@ -298,7 +297,7 @@ export class MongoDbAdapter< const model = await Promise.resolve(Model) const { query, - filters: { $select, $limit } + filters: { $select } } = this.filterQuery(id, params) const deleteOptions = { ...params.mongodb } const findParams = { @@ -306,7 +305,6 @@ export class MongoDbAdapter< paginate: false, query: { ...query, - ...($limit === 0 ? { $limit: 0 } : {}), $select } }