From 2f973bc81730522734d12c469b450a396e5fb7e3 Mon Sep 17 00:00:00 2001 From: Matt Hamann Date: Wed, 9 Nov 2022 00:03:57 -0500 Subject: [PATCH 1/5] fix(express): wait for app cfg before user fetch --- package-lock.json | 1100 +++++++++++++++++++++++++++++++++++++++++- package.json | 1 + src/express/index.ts | 130 ++--- src/index.ts | 38 +- src/lib/core.ts | 110 +---- src/lib/rownd.ts | 115 +++++ src/types.d.ts | 1 + test/client.test.ts | 49 +- test/core.test.ts | 27 +- test/mocks.ts | 185 +++++++ yarn.lock | 350 +++++++++++++- 11 files changed, 1855 insertions(+), 251 deletions(-) create mode 100644 src/lib/rownd.ts create mode 100644 test/mocks.ts diff --git a/package-lock.json b/package-lock.json index bfd3c8b..fa9e973 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "commitlint": "^17.0.3", "express": "^4.17.2", "husky": "^7.0.4", + "msw": "^0.48.0", "release-it": "^15.3.0", "size-limit": "^7.0.8", "tsdx": "^0.14.1", @@ -2737,6 +2738,38 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@mswjs/cookies": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@mswjs/cookies/-/cookies-0.2.2.tgz", + "integrity": "sha512-mlN83YSrcFgk7Dm1Mys40DLssI1KdJji2CMKN8eOlBqsTADYzj2+jWzsANsUTFbxDMWPD5e9bfA1RGqBpS3O1g==", + "dev": true, + "dependencies": { + "@types/set-cookie-parser": "^2.4.0", + "set-cookie-parser": "^2.4.6" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@mswjs/interceptors": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.17.6.tgz", + "integrity": "sha512-201pBIWehTURb6q8Gheu4Zhvd3Ox1U4BJq5KiOQsYzkWyfiOG4pwcz5hPZIEryztgrf8/sdwABpvY757xMmfrQ==", + "dev": true, + "dependencies": { + "@open-draft/until": "^1.0.3", + "@types/debug": "^4.1.7", + "@xmldom/xmldom": "^0.8.3", + "debug": "^4.3.3", + "headers-polyfill": "^3.1.0", + "outvariant": "^1.2.1", + "strict-event-emitter": "^0.2.4", + "web-encoding": "^1.1.5" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2991,6 +3024,12 @@ "@octokit/openapi-types": "^12.11.0" } }, + "node_modules/@open-draft/until": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-1.0.3.tgz", + "integrity": "sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==", + "dev": true + }, "node_modules/@pnpm/network.ca-file": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.1.tgz", @@ -3339,6 +3378,12 @@ "@types/node": "*" } }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "dev": true + }, "node_modules/@types/debug": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", @@ -3432,6 +3477,12 @@ "pretty-format": "^25.2.1" } }, + "node_modules/@types/js-levenshtein": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/js-levenshtein/-/js-levenshtein-1.1.1.tgz", + "integrity": "sha512-qC4bCqYGy1y/NP7dDVr7KJarn+PbX1nSpwA7JXdu0HxT3QYjO8MJ+cntENtHFVy2dRAyBV23OZ6MxsW1AM1L8g==", + "dev": true + }, "node_modules/@types/json-schema": { "version": "7.0.9", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", @@ -3556,6 +3607,15 @@ "@types/node": "*" } }, + "node_modules/@types/set-cookie-parser": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@types/set-cookie-parser/-/set-cookie-parser-2.4.2.tgz", + "integrity": "sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/stack-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", @@ -3723,6 +3783,22 @@ "node": ">=10" } }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.6", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.6.tgz", + "integrity": "sha512-uRjjusqpoqfmRkTaNuLJ2VohVr67Q5YwDATW3VU7PfzTj6IRaihGrYI7zckGZjxQPBIp63nfvJbM+Yu5ICh0Bg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@zxing/text-encoding": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz", + "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==", + "dev": true, + "optional": true + }, "node_modules/abab": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", @@ -4178,6 +4254,18 @@ "node": ">= 4.5.0" } }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -7305,6 +7393,15 @@ "node": ">= 0.6" } }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/exec-sh": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", @@ -7816,6 +7913,15 @@ "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", "dev": true }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -7978,14 +8084,14 @@ } }, "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", "dev": true, "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", - "has-symbols": "^1.0.1" + "has-symbols": "^1.0.3" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -8428,6 +8534,18 @@ "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", "dev": true }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/got": { "version": "11.8.3", "resolved": "https://registry.npmjs.org/got/-/got-11.8.3.tgz", @@ -8458,6 +8576,15 @@ "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, + "node_modules/graphql": { + "version": "16.6.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.6.0.tgz", + "integrity": "sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, "node_modules/growly": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", @@ -8549,9 +8676,9 @@ } }, "node_modules/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true, "engines": { "node": ">= 0.4" @@ -8626,6 +8753,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/headers-polyfill": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-3.1.2.tgz", + "integrity": "sha512-tWCK4biJ6hcLqTviLXVR9DTRfYGQMXEIUj3gwJ2rZ5wO/at3XtkI4g8mCvFdUF9l1KMBNCfmNAdnahm1cgavQA==", + "dev": true + }, "node_modules/hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -9211,6 +9344,21 @@ "node": ">=6" } }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -9275,6 +9423,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-node-process": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.0.1.tgz", + "integrity": "sha512-5IcdXuf++TTNt3oGl9EBdkvndXA8gmc4bz/Y+mdEpWh3Mcn/+kOw6hI7LD5CocqJWMzeb0I0ClndRVNdEPuJXQ==", + "dev": true + }, "node_modules/is-npm": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz", @@ -9459,6 +9613,25 @@ "node": ">=0.10.0" } }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -10285,6 +10458,15 @@ "integrity": "sha512-GxJWybWU4NV0RNKi6EIqk6IRPOTqd/h+U7sbtyuD7yUISUzV78LdHnq2xkevJsTlz/EImux4sWj+wfMiwKLkiw==", "dev": true }, + "node_modules/js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -11250,6 +11432,370 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/msw": { + "version": "0.48.0", + "resolved": "https://registry.npmjs.org/msw/-/msw-0.48.0.tgz", + "integrity": "sha512-bInpCikiW1VnjNkEjdaL5Wj+P/Xgz/U1GiUH/++Ck96w+FRpegP38HqBHJjdYZM1oH8VrtGiT14xvQHHhUTDzQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@mswjs/cookies": "^0.2.2", + "@mswjs/interceptors": "^0.17.5", + "@open-draft/until": "^1.0.3", + "@types/cookie": "^0.4.1", + "@types/js-levenshtein": "^1.1.1", + "chalk": "4.1.1", + "chokidar": "^3.4.2", + "cookie": "^0.4.2", + "graphql": "^15.0.0 || ^16.0.0", + "headers-polyfill": "^3.1.0", + "inquirer": "^8.2.0", + "is-node-process": "^1.0.1", + "js-levenshtein": "^1.1.6", + "node-fetch": "^2.6.7", + "outvariant": "^1.3.0", + "path-to-regexp": "^6.2.0", + "statuses": "^2.0.0", + "strict-event-emitter": "^0.2.6", + "type-fest": "^2.19.0", + "yargs": "^17.3.1" + }, + "bin": { + "msw": "cli/index.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mswjs" + }, + "peerDependencies": { + "typescript": ">= 4.2.x <= 4.8.x" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/msw/node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/msw/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/msw/node_modules/chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/msw/node_modules/cli-spinners": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", + "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/msw/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/msw/node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/msw/node_modules/inquirer": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", + "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/msw/node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/msw/node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/msw/node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/msw/node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/msw/node_modules/path-to-regexp": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", + "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", + "dev": true + }, + "node_modules/msw/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/msw/node_modules/rxjs": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz", + "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/msw/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/msw/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/msw/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/msw/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/msw/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/msw/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/msw/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/msw/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/msw/node_modules/yargs": { + "version": "17.6.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", + "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/msw/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", @@ -11850,6 +12396,12 @@ "node": ">=0.10.0" } }, + "node_modules/outvariant": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.3.0.tgz", + "integrity": "sha512-yeWM9k6UPfG/nzxdaPlJkB2p08hCg4xP6Lx99F+vP8YF7xyZVfTmJjrrNalkmzudD4WFvNLVudQikqUmF8zhVQ==", + "dev": true + }, "node_modules/p-cancelable": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", @@ -14542,6 +15094,12 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, + "node_modules/set-cookie-parser": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.1.tgz", + "integrity": "sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==", + "dev": true + }, "node_modules/set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", @@ -15096,6 +15654,15 @@ "node": ">=0.10.0" } }, + "node_modules/strict-event-emitter": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.2.8.tgz", + "integrity": "sha512-KDf/ujU8Zud3YaLtMCcTI4xkZlZVIYxTLr+XIULexP+77EEVWixeXroLUXQXiVtH4XH2W7jr/3PT1v3zBuvc3A==", + "dev": true, + "dependencies": { + "events": "^3.3.0" + } + }, "node_modules/string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", @@ -16370,6 +16937,19 @@ "node": ">=0.10.0" } }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -16547,6 +17127,18 @@ "defaults": "^1.0.3" } }, + "node_modules/web-encoding": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/web-encoding/-/web-encoding-1.1.5.tgz", + "integrity": "sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==", + "dev": true, + "dependencies": { + "util": "^0.12.3" + }, + "optionalDependencies": { + "@zxing/text-encoding": "0.9.0" + } + }, "node_modules/web-streams-polyfill": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", @@ -16622,6 +17214,26 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/widest-line": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", @@ -19012,8 +19624,34 @@ "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@mswjs/cookies": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@mswjs/cookies/-/cookies-0.2.2.tgz", + "integrity": "sha512-mlN83YSrcFgk7Dm1Mys40DLssI1KdJji2CMKN8eOlBqsTADYzj2+jWzsANsUTFbxDMWPD5e9bfA1RGqBpS3O1g==", + "dev": true, + "requires": { + "@types/set-cookie-parser": "^2.4.0", + "set-cookie-parser": "^2.4.6" + } + }, + "@mswjs/interceptors": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.17.6.tgz", + "integrity": "sha512-201pBIWehTURb6q8Gheu4Zhvd3Ox1U4BJq5KiOQsYzkWyfiOG4pwcz5hPZIEryztgrf8/sdwABpvY757xMmfrQ==", + "dev": true, + "requires": { + "@open-draft/until": "^1.0.3", + "@types/debug": "^4.1.7", + "@xmldom/xmldom": "^0.8.3", + "debug": "^4.3.3", + "headers-polyfill": "^3.1.0", + "outvariant": "^1.2.1", + "strict-event-emitter": "^0.2.4", + "web-encoding": "^1.1.5" } }, "@nodelib/fs.scandir": { @@ -19212,6 +19850,12 @@ "@octokit/openapi-types": "^12.11.0" } }, + "@open-draft/until": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-1.0.3.tgz", + "integrity": "sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==", + "dev": true + }, "@pnpm/network.ca-file": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.1.tgz", @@ -19482,6 +20126,12 @@ "@types/node": "*" } }, + "@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "dev": true + }, "@types/debug": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", @@ -19575,6 +20225,12 @@ "pretty-format": "^25.2.1" } }, + "@types/js-levenshtein": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/js-levenshtein/-/js-levenshtein-1.1.1.tgz", + "integrity": "sha512-qC4bCqYGy1y/NP7dDVr7KJarn+PbX1nSpwA7JXdu0HxT3QYjO8MJ+cntENtHFVy2dRAyBV23OZ6MxsW1AM1L8g==", + "dev": true + }, "@types/json-schema": { "version": "7.0.9", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", @@ -19699,6 +20355,15 @@ "@types/node": "*" } }, + "@types/set-cookie-parser": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@types/set-cookie-parser/-/set-cookie-parser-2.4.2.tgz", + "integrity": "sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/stack-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", @@ -19801,6 +20466,19 @@ } } }, + "@xmldom/xmldom": { + "version": "0.8.6", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.6.tgz", + "integrity": "sha512-uRjjusqpoqfmRkTaNuLJ2VohVr67Q5YwDATW3VU7PfzTj6IRaihGrYI7zckGZjxQPBIp63nfvJbM+Yu5ICh0Bg==", + "dev": true + }, + "@zxing/text-encoding": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz", + "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==", + "dev": true, + "optional": true + }, "abab": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", @@ -20139,6 +20817,12 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true + }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -22556,6 +23240,12 @@ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", "dev": true }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, "exec-sh": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", @@ -22973,6 +23663,15 @@ "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", "dev": true }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "requires": { + "is-callable": "^1.1.3" + } + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -23092,14 +23791,14 @@ "dev": true }, "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", "dev": true, "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", - "has-symbols": "^1.0.1" + "has-symbols": "^1.0.3" } }, "get-package-type": { @@ -23448,6 +24147,15 @@ "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", "dev": true }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, "got": { "version": "11.8.3", "resolved": "https://registry.npmjs.org/got/-/got-11.8.3.tgz", @@ -23472,6 +24180,12 @@ "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, + "graphql": { + "version": "16.6.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.6.0.tgz", + "integrity": "sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==", + "dev": true + }, "growly": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", @@ -23536,9 +24250,9 @@ "dev": true }, "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true }, "has-tostringtag": { @@ -23588,6 +24302,12 @@ "integrity": "sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==", "dev": true }, + "headers-polyfill": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-3.1.2.tgz", + "integrity": "sha512-tWCK4biJ6hcLqTviLXVR9DTRfYGQMXEIUj3gwJ2rZ5wO/at3XtkI4g8mCvFdUF9l1KMBNCfmNAdnahm1cgavQA==", + "dev": true + }, "hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -24009,6 +24729,15 @@ "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true }, + "is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -24052,6 +24781,12 @@ "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", "dev": true }, + "is-node-process": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.0.1.tgz", + "integrity": "sha512-5IcdXuf++TTNt3oGl9EBdkvndXA8gmc4bz/Y+mdEpWh3Mcn/+kOw6hI7LD5CocqJWMzeb0I0ClndRVNdEPuJXQ==", + "dev": true + }, "is-npm": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz", @@ -24176,6 +24911,19 @@ "text-extensions": "^1.0.0" } }, + "is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -24830,6 +25578,12 @@ "integrity": "sha512-GxJWybWU4NV0RNKi6EIqk6IRPOTqd/h+U7sbtyuD7yUISUzV78LdHnq2xkevJsTlz/EImux4sWj+wfMiwKLkiw==", "dev": true }, + "js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", + "dev": true + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -25583,6 +26337,262 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "msw": { + "version": "0.48.0", + "resolved": "https://registry.npmjs.org/msw/-/msw-0.48.0.tgz", + "integrity": "sha512-bInpCikiW1VnjNkEjdaL5Wj+P/Xgz/U1GiUH/++Ck96w+FRpegP38HqBHJjdYZM1oH8VrtGiT14xvQHHhUTDzQ==", + "dev": true, + "requires": { + "@mswjs/cookies": "^0.2.2", + "@mswjs/interceptors": "^0.17.5", + "@open-draft/until": "^1.0.3", + "@types/cookie": "^0.4.1", + "@types/js-levenshtein": "^1.1.1", + "chalk": "4.1.1", + "chokidar": "^3.4.2", + "cookie": "^0.4.2", + "graphql": "^15.0.0 || ^16.0.0", + "headers-polyfill": "^3.1.0", + "inquirer": "^8.2.0", + "is-node-process": "^1.0.1", + "js-levenshtein": "^1.1.6", + "node-fetch": "^2.6.7", + "outvariant": "^1.3.0", + "path-to-regexp": "^6.2.0", + "statuses": "^2.0.0", + "strict-event-emitter": "^0.2.6", + "type-fest": "^2.19.0", + "yargs": "^17.3.1" + }, + "dependencies": { + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "cli-spinners": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", + "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", + "dev": true + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true + }, + "inquirer": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", + "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + } + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + } + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "requires": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + } + }, + "path-to-regexp": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", + "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", + "dev": true + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "rxjs": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz", + "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==", + "dev": true, + "requires": { + "tslib": "^2.1.0" + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yargs": { + "version": "17.6.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", + "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "dev": true, + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true + } + } + }, "mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", @@ -26028,6 +27038,12 @@ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, + "outvariant": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.3.0.tgz", + "integrity": "sha512-yeWM9k6UPfG/nzxdaPlJkB2p08hCg4xP6Lx99F+vP8YF7xyZVfTmJjrrNalkmzudD4WFvNLVudQikqUmF8zhVQ==", + "dev": true + }, "p-cancelable": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", @@ -28021,6 +29037,12 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, + "set-cookie-parser": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.1.tgz", + "integrity": "sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==", + "dev": true + }, "set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", @@ -28482,6 +29504,15 @@ "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", "dev": true }, + "strict-event-emitter": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.2.8.tgz", + "integrity": "sha512-KDf/ujU8Zud3YaLtMCcTI4xkZlZVIYxTLr+XIULexP+77EEVWixeXroLUXQXiVtH4XH2W7jr/3PT1v3zBuvc3A==", + "dev": true, + "requires": { + "events": "^3.3.0" + } + }, "string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", @@ -29463,6 +30494,19 @@ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true }, + "util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -29609,6 +30653,16 @@ "defaults": "^1.0.3" } }, + "web-encoding": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/web-encoding/-/web-encoding-1.1.5.tgz", + "integrity": "sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==", + "dev": true, + "requires": { + "@zxing/text-encoding": "0.9.0", + "util": "^0.12.3" + } + }, "web-streams-polyfill": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", @@ -29675,6 +30729,20 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + } + }, "widest-line": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", diff --git a/package.json b/package.json index c3cd527..0dd4051 100644 --- a/package.json +++ b/package.json @@ -82,6 +82,7 @@ "commitlint": "^17.0.3", "express": "^4.17.2", "husky": "^7.0.4", + "msw": "^0.48.0", "release-it": "^15.3.0", "size-limit": "^7.0.8", "tsdx": "^0.14.1", diff --git a/src/express/index.ts b/src/express/index.ts index 5507f70..d818425 100644 --- a/src/express/index.ts +++ b/src/express/index.ts @@ -1,79 +1,81 @@ import * as express from 'express'; -import { validateToken, fetchUserInfo } from '../lib/core'; import { WrappedError } from '../errors'; -import { TConfig, TTokenValidationPayload } from '../types'; +import { IRowndExpressClient, TTokenValidationPayload } from "../types"; +import { RowndInstance } from "../lib/rownd"; type AuthenticateOpts = { - fetchUserInfo?: boolean; - errOnInvalidToken?: boolean; + fetchUserInfo?: boolean; + errOnInvalidToken?: boolean; }; type RowndRequest = express.Request & { - authenticated: boolean; - isAuthenticated: boolean; - tokenInfo: TTokenValidationPayload; - user?: { - [key: string]: any; - }; + authenticated: boolean; + isAuthenticated: boolean; + tokenInfo: TTokenValidationPayload; + user?: { + [key: string]: any; + }; }; -export default function expressLib(config: TConfig) { - function authenticate(opts: AuthenticateOpts) { - opts = { - fetchUserInfo: false, - errOnInvalidToken: true, - ...opts, - }; +export class RowndExpressClient implements IRowndExpressClient { - return ( - req: RowndRequest, - _: express.Response, - next: express.NextFunction - ) => { - req.authenticated = req.isAuthenticated = false; - let authHeader = req.get('authorization'); - authHeader = authHeader?.replace(/^bearer /i, ''); + private rownd: RowndInstance; - if (!authHeader) { - let err = new Error( - 'Missing or badly formatted authorization header. Expected: "Authorization: Bearer "' - ); - return opts.errOnInvalidToken ? next(err) : next(); - } + constructor(rownd: RowndInstance) { + this.rownd = rownd; + } - // Hide the async nature of this function from Express - (async ( - req: RowndRequest, - _: express.Response, - next: express.NextFunction - ) => { - try { - let tokenInfo = await validateToken(authHeader, { config }); - req.tokenInfo = tokenInfo; - req.authenticated = req.isAuthenticated = true; + public authenticate(opts: AuthenticateOpts) { + opts = { + fetchUserInfo: false, + errOnInvalidToken: true, + ...opts, + }; - if (opts.fetchUserInfo) { - let userInfo = await fetchUserInfo( - { user_id: tokenInfo.user_id }, - config - ); - req.user = userInfo.data; - } + return ( + req: RowndRequest, + _: express.Response, + next: express.NextFunction + ) => { + req.authenticated = req.isAuthenticated = false; + let authHeader = req.get('authorization'); + authHeader = authHeader?.replace(/^bearer /i, ''); - next(); - } catch (err) { - let wrappingError = new WrappedError( - `The provided token was invalid. Reason: ${(err as Error).message}` - ); - wrappingError.innerError = err as Error; - wrappingError.statusCode = 401; - opts.errOnInvalidToken ? next(wrappingError) : next(); - } - })(req, _, next); - }; - } + if (!authHeader) { + let err = new Error( + 'Missing or badly formatted authorization header. Expected: "Authorization: Bearer "' + ); + return opts.errOnInvalidToken ? next(err) : next(); + } + + // Hide the async nature of this function from Express + (async ( + req: RowndRequest, + _: express.Response, + next: express.NextFunction + ) => { + try { + let tokenInfo = await this.rownd.validateToken(authHeader); + req.tokenInfo = tokenInfo; + req.authenticated = req.isAuthenticated = true; + + if (opts.fetchUserInfo) { + let userInfo = await this.rownd.fetchUserInfo( + { user_id: tokenInfo.user_id } + ); + req.user = userInfo.data; + } - return { - authenticate, - }; -} + next(); + } catch (err) { + let wrappingError = new WrappedError( + `The provided token was invalid. Reason: ${(err as Error).message}` + ); + wrappingError.innerError = err as Error; + wrappingError.statusCode = 401; + opts.errOnInvalidToken ? next(wrappingError) : next(); + } + })(req, _, next); + }; + } +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 737a261..792558f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,24 +1,12 @@ import { - validateToken, - fetchUserInfo, - fetchAppConfig, - createOrUpdateUser, CLAIM_USER_ID, CLAIM_IS_VERIFIED_USER, - deleteUser, } from './lib/core'; -import { createSmartLink } from './lib/smart_links'; -import expressLib from './express'; import { - CreateSmartLinkOpts, IRowndClient, - RowndUser, TConfig, - FetchUserInfoOpts, } from './types'; -import { createConfig } from './lib/config'; - -const defaultConfig = createConfig(); +import { RowndInstance } from './lib/rownd'; const claims = { CLAIM_USER_ID, @@ -26,29 +14,7 @@ const claims = { }; function createInstance(config?: TConfig): IRowndClient { - const instConfig = { ...defaultConfig, ...config }; - var initHandle; - - if (instConfig.app_key) { - initHandle = fetchAppConfig(instConfig) - .then(app => (instConfig._app = app)) - .catch(err => { - throw new Error(`Failed to fetch app config: ${err.message}`); - }); - } - - return { - validateToken: (token: string) => - validateToken(token, { config: instConfig }), - fetchUserInfo: (opts: FetchUserInfoOpts) => fetchUserInfo(opts, instConfig), - createOrUpdateUser: (user: RowndUser) => - createOrUpdateUser(user, instConfig), - deleteUser: (userId: String) => deleteUser(userId, instConfig), - createSmartLink: (opts: CreateSmartLinkOpts) => - createSmartLink(opts, instConfig), - express: expressLib(instConfig), - appConfig: initHandle, - }; + return new RowndInstance(config); } export { createInstance, claims }; diff --git a/src/lib/core.ts b/src/lib/core.ts index de7a546..6a42691 100644 --- a/src/lib/core.ts +++ b/src/lib/core.ts @@ -3,12 +3,7 @@ import NodeCache from 'node-cache'; import * as jose from 'jose'; import { GetKeyFunction } from 'jose/dist/types/types'; import { - FetchUserInfoOpts, - RowndToken, - RowndUser, TApp, - TConfig, - TTokenValidationPayload, } from '../types'; type WellKnownConfig = { @@ -32,10 +27,6 @@ type WellKnownConfig = { export const CLAIM_USER_ID = 'https://auth.rownd.io/app_user_id'; export const CLAIM_IS_VERIFIED_USER = 'https://auth.rownd.io/is_verified_user'; -type ValidateTokenOpts = { - config: TConfig; -}; - type TAppResp = { app: TApp; }; @@ -57,7 +48,7 @@ export async function fetchRowndWellKnownConfig( return resp; } -async function fetchRowndJwks( +export async function fetchRowndJwks( jwksUrl: string ): Promise> { if (cache.has('jwks')) { @@ -70,102 +61,17 @@ async function fetchRowndJwks( return jose.createLocalJWKSet(resp); } -export async function validateToken( - token: string, - { config }: ValidateTokenOpts -): Promise { - let authConfig = await fetchRowndWellKnownConfig(config.api_url); - - let keystore = await fetchRowndJwks(authConfig.jwks_uri); - - let verifyResp = await jose.jwtVerify(token, keystore); - const payload = verifyResp.payload as RowndToken; - - return { - decoded_token: payload, - user_id: payload[CLAIM_USER_ID], - access_token: token, - }; -} - -export async function fetchUserInfo( - opts: FetchUserInfoOpts, - config: TConfig -): Promise> { - let appId = opts?.app_id || config._app?.id; - - if (!appId) { - throw new Error('An app_id must be provided'); - } - - let userId = opts.user_id; - let headers: Record = {}; - - userId = opts.user_id; - headers['x-rownd-app-key'] = config.app_key!; - headers['x-rownd-app-secret'] = config.app_secret!; - - if (cache.has(`user:${userId}`)) { - return cache.get(`user:${userId}`) as any; - } - - let resp: Record = await got - .get(`${config.api_url}/applications/${appId}/users/${userId}/data`, { - headers, - }) - .json(); - - cache.set(`user:${userId}`, resp, 300); - - return resp; -} - -export async function fetchAppConfig(config: TConfig): Promise { +export async function fetchAppConfig(apiUrl: string, appKey: string): Promise { let resp: TAppResp = await got - .get(`${config.api_url}/hub/app-config`, { + .get(`${apiUrl}/hub/app-config`, { headers: { - 'x-rownd-app-key': config.app_key, + 'x-rownd-app-key': appKey }, - }) - .json(); - return resp.app; -} - -export async function createOrUpdateUser( - user: RowndUser, - config: TConfig -): Promise { - let resp: RowndUser = await got - .put( - `${config.api_url}/applications/${config._app!.id}/users/${user.id}/data`, - { - headers: { - 'x-rownd-app-key': config.app_key, - 'x-rownd-app-secret': config.app_secret, - 'content-type': 'application/json', - }, - json: { - data: user.data, - }, + retry: { + limit: Infinity // retry forever so we hopefully don't leave the system in a bad state permanently } - ) + }) .json(); - return resp; -} - -export async function deleteUser( - userId: String, - config: TConfig -): Promise { - await got.delete( - `${config.api_url}/applications/${config._app!.id}/users/${userId}/data`, - { - headers: { - 'x-rownd-app-key': config.app_key, - 'x-rownd-app-secret': config.app_secret, - 'content-type': 'application/json', - }, - } - ); + return resp.app; } diff --git a/src/lib/rownd.ts b/src/lib/rownd.ts new file mode 100644 index 0000000..e99fc39 --- /dev/null +++ b/src/lib/rownd.ts @@ -0,0 +1,115 @@ +import * as jose from 'jose'; +import { createConfig } from "./config"; +import { CLAIM_USER_ID, fetchAppConfig, fetchRowndJwks, fetchRowndWellKnownConfig } from "./core"; +import { createSmartLink } from "./smart_links"; +import { CreateSmartLinkOpts, FetchUserInfoOpts, IRowndClient, IRowndExpressClient, RowndToken, RowndUser, TApp, TConfig } from "../types"; +import { RowndExpressClient } from "../express"; +import NodeCache from 'node-cache'; +import got from './got'; + +export class RowndInstance implements IRowndClient { + private cache = new NodeCache({ stdTTL: 3600 }); + private config: TConfig; + + private initPromise?: Promise; + + public appConfig: Promise | undefined; + + public express: IRowndExpressClient; + + constructor(pConfig?: Partial) { + this.config = createConfig(pConfig); + + this.express = new RowndExpressClient(this); + + this.initPromise = fetchAppConfig(this.config.api_url, this.config.app_key!) + .then(app => (this.config._app = app)) + .catch(err => { + throw new Error(`Failed to fetch app config: ${err.message}`); + }); + } + + async validateToken(token: string) { + let authConfig = await fetchRowndWellKnownConfig(this.config.api_url); + + let keystore = await fetchRowndJwks(authConfig.jwks_uri); + + let verifyResp = await jose.jwtVerify(token, keystore); + const payload = verifyResp.payload as RowndToken; + + return { + decoded_token: payload, + user_id: payload[CLAIM_USER_ID], + access_token: token, + }; + } + + async fetchUserInfo(opts: FetchUserInfoOpts) { + await this.initPromise; // Ensure we have the app config before fetching user info. + + let appId = opts?.app_id || this.config._app?.id; + + if (!appId) { + throw new Error('An app_id must be provided'); + } + + let userId = opts.user_id; + let headers: Record = {}; + + headers['x-rownd-app-key'] = this.config.app_key!; + headers['x-rownd-app-secret'] = this.config.app_secret!; + + if (this.cache.has(`user:${userId}`)) { + return this.cache.get(`user:${userId}`) as any; + } + + let resp: Record = await got + .get(`${this.config.api_url}/applications/${appId}/users/${userId}/data`, { + headers, + }) + .json(); + + this.cache.set(`user:${userId}`, resp, 300); + + return resp; + } + + async createOrUpdateUser(user: RowndUser) { + await this.initPromise; // Ensure we have the app config before fetching user info. + + let resp: RowndUser = await got + .put( + `${this.config.api_url}/applications/${this.config._app!.id}/users/${user.id || user.data.user_id}/data`, + { + headers: { + 'x-rownd-app-key': this.config.app_key, + 'x-rownd-app-secret': this.config.app_secret, + 'content-type': 'application/json', + }, + json: { + data: user.data, + }, + } + ) + .json(); + + return resp; + } + + async deleteUser(userId: String) { + await got.delete( + `${this.config.api_url}/applications/${this.config._app!.id}/users/${userId}/data`, + { + headers: { + 'x-rownd-app-key': this.config.app_key, + 'x-rownd-app-secret': this.config.app_secret, + 'content-type': 'application/json', + }, + } + ); + } + + async createSmartLink(opts: CreateSmartLinkOpts) { + return createSmartLink(opts, this.config); + } +} diff --git a/src/types.d.ts b/src/types.d.ts index b02ea17..c5c4120 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -2,6 +2,7 @@ export type TConfig = { api_url: string; app_key?: string; app_secret?: string; + app_id?: string; _app?: TApp; }; diff --git a/test/client.test.ts b/test/client.test.ts index cc361e3..8b90a47 100644 --- a/test/client.test.ts +++ b/test/client.test.ts @@ -1,34 +1,51 @@ import { createInstance } from '../src'; -import { createConfig } from '../src/lib/config'; -import { TConfig } from '../src/types'; +import { generateTestToken, server } from './mocks'; +import * as jose from 'jose'; +import { getKeys } from './mocks'; +import { CLAIM_USER_ID } from '../src/lib/core'; // const TOKEN: string = process.env.TOKEN as string; -const testConfig: TConfig = createConfig({ - api_url: process.env.API_URL, - app_key: process.env.APP_KEY, - app_secret: process.env.APP_SECRET, -}); +const testConfig = { + api_url: 'https://mock-api.local', + app_key: 'node-test-app-key', + app_secret: 'node-test-app-secret' +}; +// We're creating this instance before the mock server starts +// in order to test that retrieving the app config will retry. +// It will fail initially since the server isn't running until +// after the client instance is instantiated. const client = createInstance(testConfig); describe('user profile handling', () => { beforeAll(() => { - return client.appConfig; // ensure app config has been fetched + server.listen(); }); - // it('validate a good token', async () => { - // const tokenObj = await client.validateToken(TOKEN); - // expect(tokenObj.user_id).toBeDefined(); - // }); - it('fetches a user', async () => { - const user = await client.fetchUserInfo({ user_id: 'mth-test-user-1' }); - expect(user.data).toBeDefined(); + beforeEach(() => { + server.resetHandlers(); + }); + + afterAll(() => { + server.close(); + return new Promise(resolve => setTimeout(() => resolve(null), 100)); }); + it('validate a good token', async () => { + const jwt = await generateTestToken(); + const tokenObj = await client.validateToken(jwt); + expect(tokenObj.user_id).toBeDefined(); + }); + + it('fetches a user before app config is ready', async () => { + const user = await client.fetchUserInfo({ user_id: 'rownd-test-user-1' }); + expect(user.data).toBeDefined(); + }, 20000); // set the test timeout to 20s to test retry logic, since the request will fire before the server is ready + it('upserts a user', async () => { const originalUser = await client.fetchUserInfo({ - user_id: 'mth-test-user-1', + user_id: 'rownd-test-user-1', }); // Make sure the user has an email address diff --git a/test/core.test.ts b/test/core.test.ts index 469aec7..8b605ee 100644 --- a/test/core.test.ts +++ b/test/core.test.ts @@ -1,19 +1,38 @@ -import { fetchRowndWellKnownConfig, validateToken } from '../src/lib/core'; +import { fetchRowndWellKnownConfig } from '../src/lib/core'; +import { createInstance } from '../src'; +import { IRowndClient } from '../src/types'; +import { server } from './mocks'; const TOKEN: string = 'eyJhbGciOiJFZERTQSIsImtpZCI6InNpZy0xNjQ0ODU5MTUwIn0.eyJqdGkiOiIwOGVkZTBlZC01NDRlLTQ2Y2ItOThmNi03NGE2NmYyMDY0ZGEiLCJhdWQiOlsiYXBwOjI5MDE2NzI4MTczMjgxMzMxNSIsImh0dHBzOi8vYXBpLmRldi5yb3duZC5pbyJdLCJzdWIiOiJhdXRoMHw2MWYzMDUzMjUxZjI0MjAwNjk0NTU5NzYiLCJpYXQiOjE2NTA2NTczNDQsImh0dHBzOi8vYXV0aC5yb3duZC5pby9hcHBfdXNlcl9pZCI6IjcxZjZjZWViLWVlMGEtNDQzNy05YjQ0LWU2MjI5ZGVmYmFiOCIsImh0dHBzOi8vYXV0aC5yb3duZC5pby9pc192ZXJpZmllZF91c2VyIjp0cnVlLCJpc3MiOiJodHRwczovL2FwaS5kZXYucm93bmQuaW8iLCJleHAiOjE2NTA2NjA5NDR9.-SNdqdbk_GLXYSFzwYgr4XOAjeEWsmoRPArFyjASHyvhylKHMdM5WvDrRDuMGlVVL8nkZZrrBRZjV0H09j8WCQ'; const testConfig = { - api_url: 'https://api.us-east-2.dev.rownd.io', + api_url: 'https://mock-api.local', }; describe('validate token', () => { + let rowndInstance: IRowndClient; + beforeAll(() => { + server.listen(); + rowndInstance = createInstance(testConfig); + }); + + afterEach(() => { + server.resetHandlers(); + }); + + afterAll(() => { + server.close(); + return new Promise(resolve => setTimeout(() => resolve(null), 100)); + }); + it('fetches well known config', async () => { - await fetchRowndWellKnownConfig(testConfig.api_url); + let resp = await fetchRowndWellKnownConfig(testConfig.api_url); + expect(resp).toBeDefined(); }); it('throws on expired token', async () => { - await expect(validateToken(TOKEN, { config: testConfig })).rejects.toThrow( + await expect(rowndInstance.validateToken(TOKEN)).rejects.toThrow( Error ); }); diff --git a/test/mocks.ts b/test/mocks.ts new file mode 100644 index 0000000..b701aaf --- /dev/null +++ b/test/mocks.ts @@ -0,0 +1,185 @@ +import { setupServer } from 'msw/node' +import { rest } from "msw"; +import * as jose from 'jose'; +import { CLAIM_USER_ID } from '../src/lib/core'; + +// Init JWK +let keyPair: Promise = jose.generateKeyPair('EdDSA', { crv: 'Ed25519' }); + +export async function getKeys() { + return keyPair; +} + +export async function generateTestToken() { + const keys = await getKeys(); + const jwt = await new jose.SignJWT({ + [CLAIM_USER_ID]: 'rownd-test-user-1', + }) + .setProtectedHeader({ alg: 'EdDSA' }) + .setIssuedAt() + .setIssuer('dev.rownd.io') + .setAudience('app:290167281732813315') + .setExpirationTime('1h') + .sign(keys.privateKey); + + return jwt; +} + +const handlers = [ + rest.get('https://mock-api.local/hub/auth/.well-known/oauth-authorization-server', (_, res, ctx) => { + return res( + ctx.json({ + "issuer": "https://api.dev.rownd.io", + "token_endpoint": "https://mock-api.local/hub/auth/token", + "jwks_uri": "https://mock-api.local/hub/auth/keys", + "userinfo_endpoint": "https://mock-api.local/me", + "response_types_supported": [ + "token" + ], + "id_token_signing_alg_values_supported": [ + "EdDSA" + ], + "grant_types_supported": [ + "refresh_token" + ], + "subject_types_supported": [ + "public" + ], + "scopes_supported": [], + "token_endpoint_auth_methods_supported": [ + "none" + ], + "claims_supported": [ + "ver", + "jti", + "iss", + "aud", + "iat", + "exp", + "cid", + "uid", + "scp", + "sub", + "https://auth.rownd.io/app_user_id", + "https://auth.rownd.io/jwt_type" + ], + "code_challenge_methods_supported": [ + "S256" + ], + "introspection_endpoint_auth_methods_supported": [ + "client_secret_basic", + "client_secret_post", + "client_secret_jwt", + "private_key_jwt", + "none" + ], + "revocation_endpoint_auth_methods_supported": [ + "none" + ], + "request_parameter_supported": true, + "request_object_signing_alg_values_supported": [ + "EdDSA" + ] + }) + ); + }), + + rest.get('https://mock-api.local/hub/auth/keys', async (_, res, ctx) => { + let keys = await getKeys(); + let jwk = await jose.exportJWK(keys.publicKey); + return res( + ctx.json({ + "keys": [ + jwk + ] + }) + ); + }), + + rest.get('https://mock-api.local/hub/app-config', (_, res, ctx) => { + return res( + ctx.json({"app":{"name":"Rownd (dev)","id":"290167281732813315","schema":{"email":{"display_name":"Email","type":"string","data_category":"pii_basic","required":false,"owned_by":"user","user_visible":true,"revoke_after":"1 month","required_retention":"none","collection_justification":"This piece of personal data is needed to make your customer experience the best it can be. We do not resell this data.","opt_out_warning":"By turning off your e-mail, your account will no longer work as designed. You may not be able to log-in, get updates, or reset your password"},"first_name":{"display_name":"First name","type":"string","data_category":"pii_basic","required":false,"owned_by":"user","user_visible":true,"revoke_after":"1 month","required_retention":"none","collection_justification":"We collect this data to personalize your Rownd experience. ","opt_out_warning":"We will not be able to call you by your first name. ","third_party_sharing":false},"last_name":{"display_name":"Last name","type":"string","data_category":"pii_basic","required":false,"owned_by":"user","user_visible":true,"revoke_after":"1 month","required_retention":"none","collection_justification":"","opt_out_warning":""},"zip_code":{"display_name":"Zip code","type":"string","data_category":"pii_basic","required":false,"owned_by":"user","user_visible":true,"revoke_after":"1 month","required_retention":"none","collection_justification":"","opt_out_warning":""},"phone_number":{"display_name":"Phone number","type":"string","data_category":"pii_basic","required":false,"owned_by":"user","user_visible":true,"revoke_after":"1 month","required_retention":"none","collection_justification":"This piece of personal data is needed to make your customer experience the best it can be. We do not resell this data."},"crypto_wallet_address":{"display_name":"Wallet Address","type":"string","data_category":"custom","required":false,"owned_by":"app","user_visible":false,"revoke_after":"never","required_retention":"none","collection_justification":"","opt_out_warning":""},"google_id":{"display_name":"Google ID","type":"string","data_category":"custom","required":false,"owned_by":"app","user_visible":false,"revoke_after":"never","required_retention":"none","collection_justification":"","opt_out_warning":""}},"user_verification_field":"email","user_verification_fields":["email","phone_number","google_id"],"icon":"https://storage-dev.rownd.io/icon-app-290167281732813315","config":{"hub":{"customizations":{"rounded_corners":true,"offset_y":72,"visual_swoops":true,"blur_background":true,"dark_mode":"disabled"},"auth":{"audience":["https://api.dev.rownd.io"],"sign_in_methods":{"email":{"enabled":true},"phone":{"enabled":true},"apple":{"enabled":false,"client_id":""},"google":{"enabled":true,"client_id":"437354109064-pmkrcopm4r88dm6jluf8av0ds06mps9k.apps.googleusercontent.com","client_secret":"********","ios_client_id":"","scopes":[""]},"crypto_wallet":{"enabled":false}},"show_app_icon":false}},"content_gates":[]}}}) + ); + }), + + rest.get('https://mock-api.local/applications/290167281732813315/users/rownd-test-user-1/data', (_, res, ctx) => { + return res( + ctx.json({ + "data":{ + "email":"juliet@rose.co", + "user_id":"rownd-test-user-1", + "first_name":"Juliet", + "last_name":"Rose", + "phone_number":"+15555551212", + "zip_code":"90210" + }, + "redacted":[ + "zip_code" + ], + "revoke_after":{ + "zip_code":"2022-08-15T16:30:39.326Z" + }, + "retain_until":{ + "email":"2022-03-01T22:13:24.833Z" + }, + "meta":{ + "modified":"2022-11-08T04:09:20.828Z", + "first_sign_in":"2022-10-25T18:04:18.503Z", + "first_sign_in_method":"token_refresh", + "last_sign_in":"2022-11-09T02:55:19.464Z", + "last_sign_in_method":"token_refresh" + }, + "verified_data":{ + "email":"mhamann@rownd.io", + "phone_number":"+19192495211" + } + }) + ); + }), + + rest.put('https://mock-api.local/applications/290167281732813315/users/rownd-test-user-1/data', (_, res, ctx) => { + return res( + ctx.json({ + "data":{ + "email":"testuser@rownd.app", + "user_id":"71f6ceeb-ee0a-4437-9b44-e6229defbab8", + "first_name":"Juliet", + "last_name":"Rose", + "phone_number":"+15555551212", + "zip_code":"90210" + }, + "redacted":[ + "zip_code" + ], + "revoke_after":{ + "zip_code":"2022-08-15T16:30:39.326Z" + }, + "retain_until":{ + "email":"2022-03-01T22:13:24.833Z" + }, + "meta":{ + "modified":"2022-11-08T04:09:20.828Z", + "first_sign_in":"2022-10-25T18:04:18.503Z", + "first_sign_in_method":"token_refresh", + "last_sign_in":"2022-11-09T02:55:19.464Z", + "last_sign_in_method":"token_refresh" + }, + "verified_data":{ + "email":"mhamann@rownd.io", + "phone_number":"+19192495211" + } + }) + ); + }), + + rest.post('https://mock-api.local/hub/auth/magic', (_, res, ctx) => { + return res( + ctx.json({ + link: 'https://mock-api.local/hub/auth/magic/complete', + app_user_id: 'test-app-user-1' + }) + ) + }), +]; + +export const server = setupServer(...handlers); \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 48f6eeb..4d62cbf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1316,6 +1316,28 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@mswjs/cookies@^0.2.2": + "integrity" "sha512-mlN83YSrcFgk7Dm1Mys40DLssI1KdJji2CMKN8eOlBqsTADYzj2+jWzsANsUTFbxDMWPD5e9bfA1RGqBpS3O1g==" + "resolved" "https://registry.npmjs.org/@mswjs/cookies/-/cookies-0.2.2.tgz" + "version" "0.2.2" + dependencies: + "@types/set-cookie-parser" "^2.4.0" + "set-cookie-parser" "^2.4.6" + +"@mswjs/interceptors@^0.17.5": + "integrity" "sha512-201pBIWehTURb6q8Gheu4Zhvd3Ox1U4BJq5KiOQsYzkWyfiOG4pwcz5hPZIEryztgrf8/sdwABpvY757xMmfrQ==" + "resolved" "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.17.6.tgz" + "version" "0.17.6" + dependencies: + "@open-draft/until" "^1.0.3" + "@types/debug" "^4.1.7" + "@xmldom/xmldom" "^0.8.3" + "debug" "^4.3.3" + "headers-polyfill" "^3.1.0" + "outvariant" "^1.2.1" + "strict-event-emitter" "^0.2.4" + "web-encoding" "^1.1.5" + "@nodelib/fs.scandir@2.1.5": "integrity" "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==" "resolved" "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" @@ -1438,6 +1460,11 @@ dependencies: "@octokit/openapi-types" "^12.11.0" +"@open-draft/until@^1.0.3": + "integrity" "sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==" + "resolved" "https://registry.npmjs.org/@open-draft/until/-/until-1.0.3.tgz" + "version" "1.0.3" + "@pnpm/network.ca-file@^1.0.1": "integrity" "sha512-gkINruT2KUhZLTaiHxwCOh1O4NVnFT0wLjWFBHmTz9vpKag/C/noIMJXBxFe4F0mYpUVX2puLwAieLYFg2NvoA==" "resolved" "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.1.tgz" @@ -1656,6 +1683,11 @@ dependencies: "@types/node" "*" +"@types/cookie@^0.4.1": + "integrity" "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + "resolved" "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz" + "version" "0.4.1" + "@types/debug@^4.1.7": "integrity" "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==" "resolved" "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz" @@ -1737,6 +1769,11 @@ "jest-diff" "^25.2.1" "pretty-format" "^25.2.1" +"@types/js-levenshtein@^1.1.1": + "integrity" "sha512-qC4bCqYGy1y/NP7dDVr7KJarn+PbX1nSpwA7JXdu0HxT3QYjO8MJ+cntENtHFVy2dRAyBV23OZ6MxsW1AM1L8g==" + "resolved" "https://registry.npmjs.org/@types/js-levenshtein/-/js-levenshtein-1.1.1.tgz" + "version" "1.1.1" + "@types/json-schema@^7.0.3": "integrity" "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==" "resolved" "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz" @@ -1840,6 +1877,13 @@ "@types/mime" "^1" "@types/node" "*" +"@types/set-cookie-parser@^2.4.0": + "integrity" "sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==" + "resolved" "https://registry.npmjs.org/@types/set-cookie-parser/-/set-cookie-parser-2.4.2.tgz" + "version" "2.4.2" + dependencies: + "@types/node" "*" + "@types/stack-utils@^1.0.1": "integrity" "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==" "resolved" "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz" @@ -1900,6 +1944,16 @@ "semver" "^7.3.2" "tsutils" "^3.17.1" +"@xmldom/xmldom@^0.8.3": + "integrity" "sha512-uRjjusqpoqfmRkTaNuLJ2VohVr67Q5YwDATW3VU7PfzTj6IRaihGrYI7zckGZjxQPBIp63nfvJbM+Yu5ICh0Bg==" + "resolved" "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.6.tgz" + "version" "0.8.6" + +"@zxing/text-encoding@0.9.0": + "integrity" "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==" + "resolved" "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz" + "version" "0.9.0" + "abab@^2.0.0": "integrity" "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==" "resolved" "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz" @@ -2252,6 +2306,11 @@ "resolved" "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz" "version" "2.1.2" +"available-typed-arrays@^1.0.5": + "integrity" "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" + "resolved" "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz" + "version" "1.0.5" + "aws-sign2@~0.7.0": "integrity" "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" "resolved" "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz" @@ -2445,6 +2504,15 @@ "resolved" "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz" "version" "2.2.0" +"bl@^4.1.0": + "integrity" "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==" + "resolved" "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz" + "version" "4.1.0" + dependencies: + "buffer" "^5.5.0" + "inherits" "^2.0.4" + "readable-stream" "^3.4.0" + "bl@^5.0.0": "integrity" "sha512-8vxFNZ0pflFfi0WXA3WQXlj6CaMEwsmh63I1CNp0q+wWv8sD0ARx1KovSQd0l2GkwrMIOyedq0EF1FxI+RCZLQ==" "resolved" "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz" @@ -2557,6 +2625,14 @@ "resolved" "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" "version" "1.1.2" +"buffer@^5.5.0": + "integrity" "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==" + "resolved" "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz" + "version" "5.7.1" + dependencies: + "base64-js" "^1.3.1" + "ieee754" "^1.1.13" + "buffer@^6.0.3": "integrity" "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==" "resolved" "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz" @@ -2732,6 +2808,14 @@ "ansi-styles" "^4.1.0" "supports-color" "^7.1.0" +"chalk@^4.1.1", "chalk@4.1.1": + "integrity" "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==" + "resolved" "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz" + "version" "4.1.1" + dependencies: + "ansi-styles" "^4.1.0" + "supports-color" "^7.1.0" + "chalk@^5.0.0", "chalk@^5.0.1", "chalk@5.0.1": "integrity" "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==" "resolved" "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz" @@ -2742,7 +2826,7 @@ "resolved" "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz" "version" "0.7.0" -"chokidar@^3.5.3": +"chokidar@^3.4.2", "chokidar@^3.5.3": "integrity" "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==" "resolved" "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz" "version" "3.5.3" @@ -2818,6 +2902,11 @@ "resolved" "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz" "version" "2.6.1" +"cli-spinners@^2.5.0": + "integrity" "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==" + "resolved" "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz" + "version" "2.7.0" + "cli-spinners@^2.6.1": "integrity" "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==" "resolved" "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz" @@ -2851,6 +2940,15 @@ "strip-ansi" "^6.0.0" "wrap-ansi" "^7.0.0" +"cliui@^8.0.1": + "integrity" "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==" + "resolved" "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz" + "version" "8.0.1" + dependencies: + "string-width" "^4.2.0" + "strip-ansi" "^6.0.1" + "wrap-ansi" "^7.0.0" + "clone-response@^1.0.2": "integrity" "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=" "resolved" "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz" @@ -3178,6 +3276,11 @@ "resolved" "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" "version" "1.0.6" +"cookie@^0.4.2": + "integrity" "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" + "resolved" "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz" + "version" "0.4.2" + "cookie@0.4.1": "integrity" "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" "resolved" "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz" @@ -3995,6 +4098,11 @@ "resolved" "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz" "version" "1.8.1" +"events@^3.3.0": + "integrity" "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + "resolved" "https://registry.npmjs.org/events/-/events-3.3.0.tgz" + "version" "3.3.0" + "exec-sh@^0.3.2": "integrity" "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==" "resolved" "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz" @@ -4379,6 +4487,13 @@ "resolved" "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz" "version" "2.0.2" +"for-each@^0.3.3": + "integrity" "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==" + "resolved" "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz" + "version" "0.3.3" + dependencies: + "is-callable" "^1.1.3" + "for-in@^1.0.2": "integrity" "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" "resolved" "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz" @@ -4511,14 +4626,14 @@ "resolved" "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" "version" "2.0.5" -"get-intrinsic@^1.0.2", "get-intrinsic@^1.1.0", "get-intrinsic@^1.1.1": - "integrity" "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==" - "resolved" "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz" - "version" "1.1.1" +"get-intrinsic@^1.0.2", "get-intrinsic@^1.1.0", "get-intrinsic@^1.1.1", "get-intrinsic@^1.1.3": + "integrity" "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==" + "resolved" "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz" + "version" "1.1.3" dependencies: "function-bind" "^1.1.1" "has" "^1.0.3" - "has-symbols" "^1.0.1" + "has-symbols" "^1.0.3" "get-package-type@^0.1.0": "integrity" "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==" @@ -4723,6 +4838,13 @@ "resolved" "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz" "version" "0.1.2" +"gopd@^1.0.1": + "integrity" "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==" + "resolved" "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz" + "version" "1.0.1" + dependencies: + "get-intrinsic" "^1.1.3" + "got@^11.8.3": "integrity" "sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg==" "resolved" "https://registry.npmjs.org/got/-/got-11.8.3.tgz" @@ -4783,6 +4905,11 @@ "resolved" "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz" "version" "4.2.10" +"graphql@^15.0.0 || ^16.0.0": + "integrity" "sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==" + "resolved" "https://registry.npmjs.org/graphql/-/graphql-16.6.0.tgz" + "version" "16.6.0" + "growly@^1.3.0": "integrity" "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=" "resolved" "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz" @@ -4833,10 +4960,10 @@ "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" "version" "4.0.0" -"has-symbols@^1.0.1", "has-symbols@^1.0.2": - "integrity" "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" - "resolved" "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz" - "version" "1.0.2" +"has-symbols@^1.0.1", "has-symbols@^1.0.2", "has-symbols@^1.0.3": + "integrity" "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + "resolved" "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" + "version" "1.0.3" "has-tostringtag@^1.0.0": "integrity" "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==" @@ -4888,6 +5015,11 @@ dependencies: "function-bind" "^1.1.1" +"headers-polyfill@^3.1.0": + "integrity" "sha512-tWCK4biJ6hcLqTviLXVR9DTRfYGQMXEIUj3gwJ2rZ5wO/at3XtkI4g8mCvFdUF9l1KMBNCfmNAdnahm1cgavQA==" + "resolved" "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-3.1.2.tgz" + "version" "3.1.2" + "hosted-git-info@^2.1.4": "integrity" "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" "resolved" "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz" @@ -5009,7 +5141,7 @@ dependencies: "safer-buffer" ">= 2.1.2 < 3" -"ieee754@^1.2.1": +"ieee754@^1.1.13", "ieee754@^1.2.1": "integrity" "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" "resolved" "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" "version" "1.2.1" @@ -5107,6 +5239,27 @@ "strip-ansi" "^6.0.0" "through" "^2.3.6" +"inquirer@^8.2.0": + "integrity" "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==" + "resolved" "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz" + "version" "8.2.5" + dependencies: + "ansi-escapes" "^4.2.1" + "chalk" "^4.1.1" + "cli-cursor" "^3.1.0" + "cli-width" "^3.0.0" + "external-editor" "^3.0.3" + "figures" "^3.0.0" + "lodash" "^4.17.21" + "mute-stream" "0.0.8" + "ora" "^5.4.1" + "run-async" "^2.4.0" + "rxjs" "^7.5.5" + "string-width" "^4.1.0" + "strip-ansi" "^6.0.0" + "through" "^2.3.6" + "wrap-ansi" "^7.0.0" + "inquirer@9.1.0": "integrity" "sha512-eukdjrBljg9t55ZnvJjvGi1OyYEzVBFsO/8o5d2MV3mc28u3x4X2kS4eJ/+9U10KiREfPkEBSeCrU/S2G/uRtw==" "resolved" "https://registry.npmjs.org/inquirer/-/inquirer-9.1.0.tgz" @@ -5176,7 +5329,7 @@ dependencies: "kind-of" "^6.0.0" -"is-arguments@^1.1.0": +"is-arguments@^1.0.4", "is-arguments@^1.1.0": "integrity" "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==" "resolved" "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz" "version" "1.1.1" @@ -5216,7 +5369,7 @@ "resolved" "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" "version" "1.1.6" -"is-callable@^1.1.4", "is-callable@^1.2.4": +"is-callable@^1.1.3", "is-callable@^1.1.4", "is-callable@^1.2.4": "integrity" "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" "resolved" "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz" "version" "1.2.4" @@ -5325,6 +5478,13 @@ "resolved" "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz" "version" "2.1.0" +"is-generator-function@^1.0.7": + "integrity" "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==" + "resolved" "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz" + "version" "1.0.10" + dependencies: + "has-tostringtag" "^1.0.0" + "is-glob@^4.0.0", "is-glob@^4.0.1", "is-glob@^4.0.3", "is-glob@~4.0.1": "integrity" "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==" "resolved" "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" @@ -5365,6 +5525,11 @@ "resolved" "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz" "version" "2.0.2" +"is-node-process@^1.0.1": + "integrity" "sha512-5IcdXuf++TTNt3oGl9EBdkvndXA8gmc4bz/Y+mdEpWh3Mcn/+kOw6hI7LD5CocqJWMzeb0I0ClndRVNdEPuJXQ==" + "resolved" "https://registry.npmjs.org/is-node-process/-/is-node-process-1.0.1.tgz" + "version" "1.0.1" + "is-npm@^6.0.0": "integrity" "sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==" "resolved" "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz" @@ -5484,11 +5649,27 @@ dependencies: "text-extensions" "^1.0.0" +"is-typed-array@^1.1.10", "is-typed-array@^1.1.3": + "integrity" "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==" + "resolved" "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz" + "version" "1.1.10" + dependencies: + "available-typed-arrays" "^1.0.5" + "call-bind" "^1.0.2" + "for-each" "^0.3.3" + "gopd" "^1.0.1" + "has-tostringtag" "^1.0.0" + "is-typedarray@^1.0.0", "is-typedarray@~1.0.0": "integrity" "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" "resolved" "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz" "version" "1.0.0" +"is-unicode-supported@^0.1.0": + "integrity" "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==" + "resolved" "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz" + "version" "0.1.0" + "is-unicode-supported@^1.1.0", "is-unicode-supported@^1.2.0": "integrity" "sha512-wH+U77omcRzevfIG8dDhTS0V9zZyweakfD01FULl97+0EHiJTTZtJqxPSkIIo/SDPv/i07k/C9jAPY+jwLLeUQ==" "resolved" "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.2.0.tgz" @@ -6015,6 +6196,11 @@ "resolved" "https://registry.npmjs.org/jpjs/-/jpjs-1.2.1.tgz" "version" "1.2.1" +"js-levenshtein@^1.1.6": + "integrity" "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==" + "resolved" "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz" + "version" "1.1.6" + "js-tokens@^3.0.0 || ^4.0.0", "js-tokens@^4.0.0": "integrity" "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" "resolved" "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" @@ -6333,6 +6519,14 @@ dependencies: "chalk" "^2.4.2" +"log-symbols@^4.1.0": + "integrity" "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==" + "resolved" "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz" + "version" "4.1.0" + dependencies: + "chalk" "^4.1.0" + "is-unicode-supported" "^0.1.0" + "log-symbols@^5.1.0": "integrity" "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==" "resolved" "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz" @@ -6635,6 +6829,32 @@ "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" "version" "2.1.3" +"msw@^0.48.0": + "integrity" "sha512-bInpCikiW1VnjNkEjdaL5Wj+P/Xgz/U1GiUH/++Ck96w+FRpegP38HqBHJjdYZM1oH8VrtGiT14xvQHHhUTDzQ==" + "resolved" "https://registry.npmjs.org/msw/-/msw-0.48.0.tgz" + "version" "0.48.0" + dependencies: + "@mswjs/cookies" "^0.2.2" + "@mswjs/interceptors" "^0.17.5" + "@open-draft/until" "^1.0.3" + "@types/cookie" "^0.4.1" + "@types/js-levenshtein" "^1.1.1" + "chalk" "4.1.1" + "chokidar" "^3.4.2" + "cookie" "^0.4.2" + "graphql" "^15.0.0 || ^16.0.0" + "headers-polyfill" "^3.1.0" + "inquirer" "^8.2.0" + "is-node-process" "^1.0.1" + "js-levenshtein" "^1.1.6" + "node-fetch" "^2.6.7" + "outvariant" "^1.3.0" + "path-to-regexp" "^6.2.0" + "statuses" "^2.0.0" + "strict-event-emitter" "^0.2.6" + "type-fest" "^2.19.0" + "yargs" "^17.3.1" + "mute-stream@0.0.8": "integrity" "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" "resolved" "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz" @@ -6989,6 +7209,21 @@ "strip-ansi" "^6.0.0" "wcwidth" "^1.0.1" +"ora@^5.4.1": + "integrity" "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==" + "resolved" "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz" + "version" "5.4.1" + dependencies: + "bl" "^4.1.0" + "chalk" "^4.1.0" + "cli-cursor" "^3.1.0" + "cli-spinners" "^2.5.0" + "is-interactive" "^1.0.0" + "is-unicode-supported" "^0.1.0" + "log-symbols" "^4.1.0" + "strip-ansi" "^6.0.0" + "wcwidth" "^1.0.1" + "ora@^6.1.2", "ora@6.1.2": "integrity" "sha512-EJQ3NiP5Xo94wJXIzAyOtSb0QEIAUu7m8t6UZ9krbz0vAJqr92JpcK/lEXg91q6B9pEGqrykkd2EQplnifDSBw==" "resolved" "https://registry.npmjs.org/ora/-/ora-6.1.2.tgz" @@ -7017,6 +7252,11 @@ "resolved" "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz" "version" "1.0.2" +"outvariant@^1.2.1", "outvariant@^1.3.0": + "integrity" "sha512-yeWM9k6UPfG/nzxdaPlJkB2p08hCg4xP6Lx99F+vP8YF7xyZVfTmJjrrNalkmzudD4WFvNLVudQikqUmF8zhVQ==" + "resolved" "https://registry.npmjs.org/outvariant/-/outvariant-1.3.0.tgz" + "version" "1.3.0" + "p-cancelable@^2.0.0": "integrity" "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==" "resolved" "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz" @@ -7233,6 +7473,11 @@ "resolved" "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" "version" "1.0.7" +"path-to-regexp@^6.2.0": + "integrity" "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==" + "resolved" "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz" + "version" "6.2.1" + "path-to-regexp@0.1.7": "integrity" "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" "resolved" "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz" @@ -8010,6 +8255,13 @@ dependencies: "tslib" "^1.9.0" +"rxjs@^7.5.5": + "integrity" "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==" + "resolved" "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz" + "version" "7.5.7" + dependencies: + "tslib" "^2.1.0" + "rxjs@^7.5.6": "integrity" "sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw==" "resolved" "https://registry.npmjs.org/rxjs/-/rxjs-7.5.6.tgz" @@ -8190,6 +8442,11 @@ "resolved" "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz" "version" "2.0.0" +"set-cookie-parser@^2.4.6": + "integrity" "sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==" + "resolved" "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.1.tgz" + "version" "2.5.1" + "set-value@^2.0.0", "set-value@^2.0.1": "integrity" "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==" "resolved" "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz" @@ -8486,6 +8743,11 @@ "define-property" "^0.2.5" "object-copy" "^0.1.0" +"statuses@^2.0.0": + "integrity" "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + "resolved" "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" + "version" "2.0.1" + "statuses@>= 1.5.0 < 2", "statuses@~1.5.0": "integrity" "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" "resolved" "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz" @@ -8496,6 +8758,13 @@ "resolved" "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz" "version" "1.1.1" +"strict-event-emitter@^0.2.4", "strict-event-emitter@^0.2.6": + "integrity" "sha512-KDf/ujU8Zud3YaLtMCcTI4xkZlZVIYxTLr+XIULexP+77EEVWixeXroLUXQXiVtH4XH2W7jr/3PT1v3zBuvc3A==" + "resolved" "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.2.8.tgz" + "version" "0.2.8" + dependencies: + "events" "^3.3.0" + "string_decoder@^1.1.1": "integrity" "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==" "resolved" "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" @@ -9069,6 +9338,11 @@ "resolved" "https://registry.npmjs.org/type-fest/-/type-fest-2.18.0.tgz" "version" "2.18.0" +"type-fest@^2.19.0": + "integrity" "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==" + "resolved" "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz" + "version" "2.19.0" + "type-fest@^2.5.1": "integrity" "sha512-pRS+/yrW5TjPPHNOvxhbNZexr2bS63WjrMU8a+VzEBhUi9Tz1pZeD+vQz3ut0svZ46P+SRqMEPnJmk2XnvNzTw==" "resolved" "https://registry.npmjs.org/type-fest/-/type-fest-2.18.0.tgz" @@ -9234,6 +9508,17 @@ "resolved" "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" "version" "1.0.2" +"util@^0.12.3": + "integrity" "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==" + "resolved" "https://registry.npmjs.org/util/-/util-0.12.5.tgz" + "version" "0.12.5" + dependencies: + "inherits" "^2.0.3" + "is-arguments" "^1.0.4" + "is-generator-function" "^1.0.7" + "is-typed-array" "^1.1.3" + "which-typed-array" "^1.1.2" + "utils-merge@1.0.1": "integrity" "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" "resolved" "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" @@ -9323,6 +9608,15 @@ dependencies: "defaults" "^1.0.3" +"web-encoding@^1.1.5": + "integrity" "sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==" + "resolved" "https://registry.npmjs.org/web-encoding/-/web-encoding-1.1.5.tgz" + "version" "1.1.5" + dependencies: + "util" "^0.12.3" + optionalDependencies: + "@zxing/text-encoding" "0.9.0" + "web-streams-polyfill@^3.0.3": "integrity" "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==" "resolved" "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz" @@ -9383,6 +9677,18 @@ "resolved" "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz" "version" "2.0.0" +"which-typed-array@^1.1.2": + "integrity" "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==" + "resolved" "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz" + "version" "1.1.9" + dependencies: + "available-typed-arrays" "^1.0.5" + "call-bind" "^1.0.2" + "for-each" "^0.3.3" + "gopd" "^1.0.1" + "has-tostringtag" "^1.0.0" + "is-typed-array" "^1.1.10" + "which@^1.2.9", "which@^1.3.1": "integrity" "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==" "resolved" "https://registry.npmjs.org/which/-/which-1.3.1.tgz" @@ -9568,6 +9874,11 @@ "resolved" "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" "version" "21.1.1" +"yargs-parser@^21.1.1": + "integrity" "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" + "resolved" "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" + "version" "21.1.1" + "yargs-parser@21.1.1": "integrity" "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" "resolved" "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" @@ -9616,6 +9927,19 @@ "y18n" "^5.0.5" "yargs-parser" "^21.0.0" +"yargs@^17.3.1": + "integrity" "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==" + "resolved" "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz" + "version" "17.6.2" + dependencies: + "cliui" "^8.0.1" + "escalade" "^3.1.1" + "get-caller-file" "^2.0.5" + "require-directory" "^2.1.1" + "string-width" "^4.2.3" + "y18n" "^5.0.5" + "yargs-parser" "^21.1.1" + "yn@3.1.1": "integrity" "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" "resolved" "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz" From 68a6b37abfe2c33e74d9658a1e3c938682a2da35 Mon Sep 17 00:00:00 2001 From: Matt Hamann Date: Wed, 9 Nov 2022 00:08:39 -0500 Subject: [PATCH 2/5] chore: lint fixes --- src/express/index.ts | 127 ++++++------ src/index.ts | 10 +- src/lib/core.ts | 15 +- src/lib/rownd.ts | 203 ++++++++++--------- test/client.test.ts | 9 +- test/core.test.ts | 4 +- test/mocks.ts | 449 +++++++++++++++++++++++++++---------------- 7 files changed, 473 insertions(+), 344 deletions(-) diff --git a/src/express/index.ts b/src/express/index.ts index d818425..e4499d1 100644 --- a/src/express/index.ts +++ b/src/express/index.ts @@ -1,81 +1,80 @@ import * as express from 'express'; import { WrappedError } from '../errors'; -import { IRowndExpressClient, TTokenValidationPayload } from "../types"; -import { RowndInstance } from "../lib/rownd"; +import { IRowndExpressClient, TTokenValidationPayload } from '../types'; +import { RowndInstance } from '../lib/rownd'; type AuthenticateOpts = { - fetchUserInfo?: boolean; - errOnInvalidToken?: boolean; + fetchUserInfo?: boolean; + errOnInvalidToken?: boolean; }; type RowndRequest = express.Request & { - authenticated: boolean; - isAuthenticated: boolean; - tokenInfo: TTokenValidationPayload; - user?: { - [key: string]: any; - }; + authenticated: boolean; + isAuthenticated: boolean; + tokenInfo: TTokenValidationPayload; + user?: { + [key: string]: any; + }; }; export class RowndExpressClient implements IRowndExpressClient { + private rownd: RowndInstance; - private rownd: RowndInstance; - - constructor(rownd: RowndInstance) { - this.rownd = rownd; - } + constructor(rownd: RowndInstance) { + this.rownd = rownd; + } - public authenticate(opts: AuthenticateOpts) { - opts = { - fetchUserInfo: false, - errOnInvalidToken: true, - ...opts, - }; + public authenticate(opts: AuthenticateOpts) { + opts = { + fetchUserInfo: false, + errOnInvalidToken: true, + ...opts, + }; - return ( - req: RowndRequest, - _: express.Response, - next: express.NextFunction - ) => { - req.authenticated = req.isAuthenticated = false; - let authHeader = req.get('authorization'); - authHeader = authHeader?.replace(/^bearer /i, ''); + return ( + req: RowndRequest, + _: express.Response, + next: express.NextFunction + ) => { + req.authenticated = req.isAuthenticated = false; + let authHeader = req.get('authorization'); + authHeader = authHeader?.replace(/^bearer /i, ''); - if (!authHeader) { - let err = new Error( - 'Missing or badly formatted authorization header. Expected: "Authorization: Bearer "' - ); - return opts.errOnInvalidToken ? next(err) : next(); - } + if (!authHeader) { + let err = new Error( + 'Missing or badly formatted authorization header. Expected: "Authorization: Bearer "' + ); + return opts.errOnInvalidToken ? next(err) : next(); + } - // Hide the async nature of this function from Express - (async ( - req: RowndRequest, - _: express.Response, - next: express.NextFunction - ) => { - try { - let tokenInfo = await this.rownd.validateToken(authHeader); - req.tokenInfo = tokenInfo; - req.authenticated = req.isAuthenticated = true; + // Hide the async nature of this function from Express + (async ( + req: RowndRequest, + _: express.Response, + next: express.NextFunction + ) => { + try { + let tokenInfo = await this.rownd.validateToken(authHeader); + req.tokenInfo = tokenInfo; + req.authenticated = req.isAuthenticated = true; - if (opts.fetchUserInfo) { - let userInfo = await this.rownd.fetchUserInfo( - { user_id: tokenInfo.user_id } - ); - req.user = userInfo.data; - } + if (opts.fetchUserInfo) { + let userInfo = await this.rownd.fetchUserInfo({ + user_id: tokenInfo.user_id, + }); + req.user = userInfo.data; + } - next(); - } catch (err) { - let wrappingError = new WrappedError( - `The provided token was invalid. Reason: ${(err as Error).message}` - ); - wrappingError.innerError = err as Error; - wrappingError.statusCode = 401; - opts.errOnInvalidToken ? next(wrappingError) : next(); - } - })(req, _, next); - }; - } -} \ No newline at end of file + next(); + } catch (err) { + let wrappingError = new WrappedError( + `The provided token was invalid. Reason: ${(err as Error).message}` + ); + wrappingError.innerError = err as Error; + wrappingError.statusCode = 401; + opts.errOnInvalidToken ? next(wrappingError) : next(); + } + })(req, _, next); + }; + } +} diff --git a/src/index.ts b/src/index.ts index 792558f..a60e13f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,11 +1,5 @@ -import { - CLAIM_USER_ID, - CLAIM_IS_VERIFIED_USER, -} from './lib/core'; -import { - IRowndClient, - TConfig, -} from './types'; +import { CLAIM_USER_ID, CLAIM_IS_VERIFIED_USER } from './lib/core'; +import { IRowndClient, TConfig } from './types'; import { RowndInstance } from './lib/rownd'; const claims = { diff --git a/src/lib/core.ts b/src/lib/core.ts index 6a42691..d1ea25b 100644 --- a/src/lib/core.ts +++ b/src/lib/core.ts @@ -2,9 +2,7 @@ import got from './got'; import NodeCache from 'node-cache'; import * as jose from 'jose'; import { GetKeyFunction } from 'jose/dist/types/types'; -import { - TApp, -} from '../types'; +import { TApp } from '../types'; type WellKnownConfig = { issuer: string; @@ -61,15 +59,18 @@ export async function fetchRowndJwks( return jose.createLocalJWKSet(resp); } -export async function fetchAppConfig(apiUrl: string, appKey: string): Promise { +export async function fetchAppConfig( + apiUrl: string, + appKey: string +): Promise { let resp: TAppResp = await got .get(`${apiUrl}/hub/app-config`, { headers: { - 'x-rownd-app-key': appKey + 'x-rownd-app-key': appKey, }, retry: { - limit: Infinity // retry forever so we hopefully don't leave the system in a bad state permanently - } + limit: Infinity, // retry forever so we hopefully don't leave the system in a bad state permanently + }, }) .json(); diff --git a/src/lib/rownd.ts b/src/lib/rownd.ts index e99fc39..fd1c735 100644 --- a/src/lib/rownd.ts +++ b/src/lib/rownd.ts @@ -1,115 +1,136 @@ import * as jose from 'jose'; -import { createConfig } from "./config"; -import { CLAIM_USER_ID, fetchAppConfig, fetchRowndJwks, fetchRowndWellKnownConfig } from "./core"; -import { createSmartLink } from "./smart_links"; -import { CreateSmartLinkOpts, FetchUserInfoOpts, IRowndClient, IRowndExpressClient, RowndToken, RowndUser, TApp, TConfig } from "../types"; -import { RowndExpressClient } from "../express"; +import { createConfig } from './config'; +import { + CLAIM_USER_ID, + fetchAppConfig, + fetchRowndJwks, + fetchRowndWellKnownConfig, +} from './core'; +import { createSmartLink } from './smart_links'; +import { + CreateSmartLinkOpts, + FetchUserInfoOpts, + IRowndClient, + IRowndExpressClient, + RowndToken, + RowndUser, + TApp, + TConfig, +} from '../types'; +import { RowndExpressClient } from '../express'; import NodeCache from 'node-cache'; import got from './got'; export class RowndInstance implements IRowndClient { - private cache = new NodeCache({ stdTTL: 3600 }); - private config: TConfig; + private cache = new NodeCache({ stdTTL: 3600 }); + private config: TConfig; - private initPromise?: Promise; + private initPromise?: Promise; - public appConfig: Promise | undefined; + public appConfig: Promise | undefined; - public express: IRowndExpressClient; + public express: IRowndExpressClient; - constructor(pConfig?: Partial) { - this.config = createConfig(pConfig); + constructor(pConfig?: Partial) { + this.config = createConfig(pConfig); - this.express = new RowndExpressClient(this); + this.express = new RowndExpressClient(this); - this.initPromise = fetchAppConfig(this.config.api_url, this.config.app_key!) - .then(app => (this.config._app = app)) - .catch(err => { - throw new Error(`Failed to fetch app config: ${err.message}`); - }); - } - - async validateToken(token: string) { - let authConfig = await fetchRowndWellKnownConfig(this.config.api_url); - - let keystore = await fetchRowndJwks(authConfig.jwks_uri); - - let verifyResp = await jose.jwtVerify(token, keystore); - const payload = verifyResp.payload as RowndToken; + this.initPromise = fetchAppConfig(this.config.api_url, this.config.app_key!) + .then(app => (this.config._app = app)) + .catch(err => { + throw new Error(`Failed to fetch app config: ${err.message}`); + }); + } - return { - decoded_token: payload, - user_id: payload[CLAIM_USER_ID], - access_token: token, - }; - } - - async fetchUserInfo(opts: FetchUserInfoOpts) { - await this.initPromise; // Ensure we have the app config before fetching user info. + async validateToken(token: string) { + let authConfig = await fetchRowndWellKnownConfig(this.config.api_url); - let appId = opts?.app_id || this.config._app?.id; + let keystore = await fetchRowndJwks(authConfig.jwks_uri); - if (!appId) { - throw new Error('An app_id must be provided'); - } + let verifyResp = await jose.jwtVerify(token, keystore); + const payload = verifyResp.payload as RowndToken; - let userId = opts.user_id; - let headers: Record = {}; + return { + decoded_token: payload, + user_id: payload[CLAIM_USER_ID], + access_token: token, + }; + } - headers['x-rownd-app-key'] = this.config.app_key!; - headers['x-rownd-app-secret'] = this.config.app_secret!; + async fetchUserInfo(opts: FetchUserInfoOpts) { + await this.initPromise; // Ensure we have the app config before fetching user info. - if (this.cache.has(`user:${userId}`)) { - return this.cache.get(`user:${userId}`) as any; - } + let appId = opts?.app_id || this.config._app?.id; - let resp: Record = await got - .get(`${this.config.api_url}/applications/${appId}/users/${userId}/data`, { - headers, - }) - .json(); - - this.cache.set(`user:${userId}`, resp, 300); - - return resp; + if (!appId) { + throw new Error('An app_id must be provided'); } - async createOrUpdateUser(user: RowndUser) { - await this.initPromise; // Ensure we have the app config before fetching user info. - - let resp: RowndUser = await got - .put( - `${this.config.api_url}/applications/${this.config._app!.id}/users/${user.id || user.data.user_id}/data`, - { - headers: { - 'x-rownd-app-key': this.config.app_key, - 'x-rownd-app-secret': this.config.app_secret, - 'content-type': 'application/json', - }, - json: { - data: user.data, - }, - } - ) - .json(); - - return resp; - } + let userId = opts.user_id; + let headers: Record = {}; - async deleteUser(userId: String) { - await got.delete( - `${this.config.api_url}/applications/${this.config._app!.id}/users/${userId}/data`, - { - headers: { - 'x-rownd-app-key': this.config.app_key, - 'x-rownd-app-secret': this.config.app_secret, - 'content-type': 'application/json', - }, - } - ); - } + headers['x-rownd-app-key'] = this.config.app_key!; + headers['x-rownd-app-secret'] = this.config.app_secret!; - async createSmartLink(opts: CreateSmartLinkOpts) { - return createSmartLink(opts, this.config); + if (this.cache.has(`user:${userId}`)) { + return this.cache.get(`user:${userId}`) as any; } + + let resp: Record = await got + .get( + `${this.config.api_url}/applications/${appId}/users/${userId}/data`, + { + headers, + } + ) + .json(); + + this.cache.set(`user:${userId}`, resp, 300); + + return resp; + } + + async createOrUpdateUser(user: RowndUser) { + await this.initPromise; // Ensure we have the app config before fetching user info. + + let resp: RowndUser = await got + .put( + `${this.config.api_url}/applications/${ + this.config._app!.id + }/users/${user.id || user.data.user_id}/data`, + { + headers: { + 'x-rownd-app-key': this.config.app_key, + 'x-rownd-app-secret': this.config.app_secret, + 'content-type': 'application/json', + }, + json: { + data: user.data, + }, + } + ) + .json(); + + return resp; + } + + async deleteUser(userId: String) { + await got.delete( + `${this.config.api_url}/applications/${ + this.config._app!.id + }/users/${userId}/data`, + { + headers: { + 'x-rownd-app-key': this.config.app_key, + 'x-rownd-app-secret': this.config.app_secret, + 'content-type': 'application/json', + }, + } + ); + } + + async createSmartLink(opts: CreateSmartLinkOpts) { + return createSmartLink(opts, this.config); + } } diff --git a/test/client.test.ts b/test/client.test.ts index 8b90a47..ea0aeb3 100644 --- a/test/client.test.ts +++ b/test/client.test.ts @@ -1,15 +1,12 @@ import { createInstance } from '../src'; import { generateTestToken, server } from './mocks'; -import * as jose from 'jose'; -import { getKeys } from './mocks'; -import { CLAIM_USER_ID } from '../src/lib/core'; // const TOKEN: string = process.env.TOKEN as string; const testConfig = { api_url: 'https://mock-api.local', app_key: 'node-test-app-key', - app_secret: 'node-test-app-secret' + app_secret: 'node-test-app-secret', }; // We're creating this instance before the mock server starts @@ -32,7 +29,7 @@ describe('user profile handling', () => { return new Promise(resolve => setTimeout(() => resolve(null), 100)); }); - it('validate a good token', async () => { + it('validate a good token', async () => { const jwt = await generateTestToken(); const tokenObj = await client.validateToken(jwt); expect(tokenObj.user_id).toBeDefined(); @@ -41,7 +38,7 @@ describe('user profile handling', () => { it('fetches a user before app config is ready', async () => { const user = await client.fetchUserInfo({ user_id: 'rownd-test-user-1' }); expect(user.data).toBeDefined(); - }, 20000); // set the test timeout to 20s to test retry logic, since the request will fire before the server is ready + }, 20000); // set the test timeout to 20s to test retry logic, since the request will fire before the server is ready it('upserts a user', async () => { const originalUser = await client.fetchUserInfo({ diff --git a/test/core.test.ts b/test/core.test.ts index 8b605ee..d4e9cad 100644 --- a/test/core.test.ts +++ b/test/core.test.ts @@ -32,8 +32,6 @@ describe('validate token', () => { }); it('throws on expired token', async () => { - await expect(rowndInstance.validateToken(TOKEN)).rejects.toThrow( - Error - ); + await expect(rowndInstance.validateToken(TOKEN)).rejects.toThrow(Error); }); }); diff --git a/test/mocks.ts b/test/mocks.ts index b701aaf..d2e6aef 100644 --- a/test/mocks.ts +++ b/test/mocks.ts @@ -1,185 +1,304 @@ -import { setupServer } from 'msw/node' -import { rest } from "msw"; +import { setupServer } from 'msw/node'; +import { rest } from 'msw'; import * as jose from 'jose'; import { CLAIM_USER_ID } from '../src/lib/core'; // Init JWK -let keyPair: Promise = jose.generateKeyPair('EdDSA', { crv: 'Ed25519' }); +let keyPair: Promise = jose.generateKeyPair( + 'EdDSA', + { crv: 'Ed25519' } +); export async function getKeys() { - return keyPair; + return keyPair; } export async function generateTestToken() { - const keys = await getKeys(); - const jwt = await new jose.SignJWT({ - [CLAIM_USER_ID]: 'rownd-test-user-1', - }) - .setProtectedHeader({ alg: 'EdDSA' }) - .setIssuedAt() - .setIssuer('dev.rownd.io') - .setAudience('app:290167281732813315') - .setExpirationTime('1h') - .sign(keys.privateKey); + const keys = await getKeys(); + const jwt = await new jose.SignJWT({ + [CLAIM_USER_ID]: 'rownd-test-user-1', + }) + .setProtectedHeader({ alg: 'EdDSA' }) + .setIssuedAt() + .setIssuer('dev.rownd.io') + .setAudience('app:290167281732813315') + .setExpirationTime('1h') + .sign(keys.privateKey); - return jwt; + return jwt; } const handlers = [ - rest.get('https://mock-api.local/hub/auth/.well-known/oauth-authorization-server', (_, res, ctx) => { - return res( - ctx.json({ - "issuer": "https://api.dev.rownd.io", - "token_endpoint": "https://mock-api.local/hub/auth/token", - "jwks_uri": "https://mock-api.local/hub/auth/keys", - "userinfo_endpoint": "https://mock-api.local/me", - "response_types_supported": [ - "token" - ], - "id_token_signing_alg_values_supported": [ - "EdDSA" - ], - "grant_types_supported": [ - "refresh_token" - ], - "subject_types_supported": [ - "public" - ], - "scopes_supported": [], - "token_endpoint_auth_methods_supported": [ - "none" - ], - "claims_supported": [ - "ver", - "jti", - "iss", - "aud", - "iat", - "exp", - "cid", - "uid", - "scp", - "sub", - "https://auth.rownd.io/app_user_id", - "https://auth.rownd.io/jwt_type" - ], - "code_challenge_methods_supported": [ - "S256" - ], - "introspection_endpoint_auth_methods_supported": [ - "client_secret_basic", - "client_secret_post", - "client_secret_jwt", - "private_key_jwt", - "none" - ], - "revocation_endpoint_auth_methods_supported": [ - "none" - ], - "request_parameter_supported": true, - "request_object_signing_alg_values_supported": [ - "EdDSA" - ] - }) - ); - }), + rest.get( + 'https://mock-api.local/hub/auth/.well-known/oauth-authorization-server', + (_, res, ctx) => { + return res( + ctx.json({ + issuer: 'https://api.dev.rownd.io', + token_endpoint: 'https://mock-api.local/hub/auth/token', + jwks_uri: 'https://mock-api.local/hub/auth/keys', + userinfo_endpoint: 'https://mock-api.local/me', + response_types_supported: ['token'], + id_token_signing_alg_values_supported: ['EdDSA'], + grant_types_supported: ['refresh_token'], + subject_types_supported: ['public'], + scopes_supported: [], + token_endpoint_auth_methods_supported: ['none'], + claims_supported: [ + 'ver', + 'jti', + 'iss', + 'aud', + 'iat', + 'exp', + 'cid', + 'uid', + 'scp', + 'sub', + 'https://auth.rownd.io/app_user_id', + 'https://auth.rownd.io/jwt_type', + ], + code_challenge_methods_supported: ['S256'], + introspection_endpoint_auth_methods_supported: [ + 'client_secret_basic', + 'client_secret_post', + 'client_secret_jwt', + 'private_key_jwt', + 'none', + ], + revocation_endpoint_auth_methods_supported: ['none'], + request_parameter_supported: true, + request_object_signing_alg_values_supported: ['EdDSA'], + }) + ); + } + ), - rest.get('https://mock-api.local/hub/auth/keys', async (_, res, ctx) => { - let keys = await getKeys(); - let jwk = await jose.exportJWK(keys.publicKey); - return res( - ctx.json({ - "keys": [ - jwk - ] - }) - ); - }), + rest.get('https://mock-api.local/hub/auth/keys', async (_, res, ctx) => { + let keys = await getKeys(); + let jwk = await jose.exportJWK(keys.publicKey); + return res( + ctx.json({ + keys: [jwk], + }) + ); + }), - rest.get('https://mock-api.local/hub/app-config', (_, res, ctx) => { - return res( - ctx.json({"app":{"name":"Rownd (dev)","id":"290167281732813315","schema":{"email":{"display_name":"Email","type":"string","data_category":"pii_basic","required":false,"owned_by":"user","user_visible":true,"revoke_after":"1 month","required_retention":"none","collection_justification":"This piece of personal data is needed to make your customer experience the best it can be. We do not resell this data.","opt_out_warning":"By turning off your e-mail, your account will no longer work as designed. You may not be able to log-in, get updates, or reset your password"},"first_name":{"display_name":"First name","type":"string","data_category":"pii_basic","required":false,"owned_by":"user","user_visible":true,"revoke_after":"1 month","required_retention":"none","collection_justification":"We collect this data to personalize your Rownd experience. ","opt_out_warning":"We will not be able to call you by your first name. ","third_party_sharing":false},"last_name":{"display_name":"Last name","type":"string","data_category":"pii_basic","required":false,"owned_by":"user","user_visible":true,"revoke_after":"1 month","required_retention":"none","collection_justification":"","opt_out_warning":""},"zip_code":{"display_name":"Zip code","type":"string","data_category":"pii_basic","required":false,"owned_by":"user","user_visible":true,"revoke_after":"1 month","required_retention":"none","collection_justification":"","opt_out_warning":""},"phone_number":{"display_name":"Phone number","type":"string","data_category":"pii_basic","required":false,"owned_by":"user","user_visible":true,"revoke_after":"1 month","required_retention":"none","collection_justification":"This piece of personal data is needed to make your customer experience the best it can be. We do not resell this data."},"crypto_wallet_address":{"display_name":"Wallet Address","type":"string","data_category":"custom","required":false,"owned_by":"app","user_visible":false,"revoke_after":"never","required_retention":"none","collection_justification":"","opt_out_warning":""},"google_id":{"display_name":"Google ID","type":"string","data_category":"custom","required":false,"owned_by":"app","user_visible":false,"revoke_after":"never","required_retention":"none","collection_justification":"","opt_out_warning":""}},"user_verification_field":"email","user_verification_fields":["email","phone_number","google_id"],"icon":"https://storage-dev.rownd.io/icon-app-290167281732813315","config":{"hub":{"customizations":{"rounded_corners":true,"offset_y":72,"visual_swoops":true,"blur_background":true,"dark_mode":"disabled"},"auth":{"audience":["https://api.dev.rownd.io"],"sign_in_methods":{"email":{"enabled":true},"phone":{"enabled":true},"apple":{"enabled":false,"client_id":""},"google":{"enabled":true,"client_id":"437354109064-pmkrcopm4r88dm6jluf8av0ds06mps9k.apps.googleusercontent.com","client_secret":"********","ios_client_id":"","scopes":[""]},"crypto_wallet":{"enabled":false}},"show_app_icon":false}},"content_gates":[]}}}) - ); - }), - - rest.get('https://mock-api.local/applications/290167281732813315/users/rownd-test-user-1/data', (_, res, ctx) => { - return res( - ctx.json({ - "data":{ - "email":"juliet@rose.co", - "user_id":"rownd-test-user-1", - "first_name":"Juliet", - "last_name":"Rose", - "phone_number":"+15555551212", - "zip_code":"90210" - }, - "redacted":[ - "zip_code" - ], - "revoke_after":{ - "zip_code":"2022-08-15T16:30:39.326Z" - }, - "retain_until":{ - "email":"2022-03-01T22:13:24.833Z" + rest.get('https://mock-api.local/hub/app-config', (_, res, ctx) => { + return res( + ctx.json({ + app: { + name: 'Rownd (dev)', + id: '290167281732813315', + schema: { + email: { + display_name: 'Email', + type: 'string', + data_category: 'pii_basic', + required: false, + owned_by: 'user', + user_visible: true, + revoke_after: '1 month', + required_retention: 'none', + collection_justification: + 'This piece of personal data is needed to make your customer experience the best it can be. We do not resell this data.', + opt_out_warning: + 'By turning off your e-mail, your account will no longer work as designed. You may not be able to log-in, get updates, or reset your password', + }, + first_name: { + display_name: 'First name', + type: 'string', + data_category: 'pii_basic', + required: false, + owned_by: 'user', + user_visible: true, + revoke_after: '1 month', + required_retention: 'none', + collection_justification: + 'We collect this data to personalize your Rownd experience. ', + opt_out_warning: + 'We will not be able to call you by your first name. ', + third_party_sharing: false, + }, + last_name: { + display_name: 'Last name', + type: 'string', + data_category: 'pii_basic', + required: false, + owned_by: 'user', + user_visible: true, + revoke_after: '1 month', + required_retention: 'none', + collection_justification: '', + opt_out_warning: '', + }, + zip_code: { + display_name: 'Zip code', + type: 'string', + data_category: 'pii_basic', + required: false, + owned_by: 'user', + user_visible: true, + revoke_after: '1 month', + required_retention: 'none', + collection_justification: '', + opt_out_warning: '', + }, + phone_number: { + display_name: 'Phone number', + type: 'string', + data_category: 'pii_basic', + required: false, + owned_by: 'user', + user_visible: true, + revoke_after: '1 month', + required_retention: 'none', + collection_justification: + 'This piece of personal data is needed to make your customer experience the best it can be. We do not resell this data.', + }, + crypto_wallet_address: { + display_name: 'Wallet Address', + type: 'string', + data_category: 'custom', + required: false, + owned_by: 'app', + user_visible: false, + revoke_after: 'never', + required_retention: 'none', + collection_justification: '', + opt_out_warning: '', + }, + google_id: { + display_name: 'Google ID', + type: 'string', + data_category: 'custom', + required: false, + owned_by: 'app', + user_visible: false, + revoke_after: 'never', + required_retention: 'none', + collection_justification: '', + opt_out_warning: '', + }, + }, + user_verification_field: 'email', + user_verification_fields: ['email', 'phone_number', 'google_id'], + icon: 'https://storage-dev.rownd.io/icon-app-290167281732813315', + config: { + hub: { + customizations: { + rounded_corners: true, + offset_y: 72, + visual_swoops: true, + blur_background: true, + dark_mode: 'disabled', + }, + auth: { + audience: ['https://api.dev.rownd.io'], + sign_in_methods: { + email: { enabled: true }, + phone: { enabled: true }, + apple: { enabled: false, client_id: '' }, + google: { + enabled: true, + client_id: + '437354109064-pmkrcopm4r88dm6jluf8av0ds06mps9k.apps.googleusercontent.com', + client_secret: '********', + ios_client_id: '', + scopes: [''], + }, + crypto_wallet: { enabled: false }, }, - "meta":{ - "modified":"2022-11-08T04:09:20.828Z", - "first_sign_in":"2022-10-25T18:04:18.503Z", - "first_sign_in_method":"token_refresh", - "last_sign_in":"2022-11-09T02:55:19.464Z", - "last_sign_in_method":"token_refresh" - }, - "verified_data":{ - "email":"mhamann@rownd.io", - "phone_number":"+19192495211" - } - }) - ); - }), + show_app_icon: false, + }, + }, + content_gates: [], + }, + }, + }) + ); + }), - rest.put('https://mock-api.local/applications/290167281732813315/users/rownd-test-user-1/data', (_, res, ctx) => { - return res( - ctx.json({ - "data":{ - "email":"testuser@rownd.app", - "user_id":"71f6ceeb-ee0a-4437-9b44-e6229defbab8", - "first_name":"Juliet", - "last_name":"Rose", - "phone_number":"+15555551212", - "zip_code":"90210" - }, - "redacted":[ - "zip_code" - ], - "revoke_after":{ - "zip_code":"2022-08-15T16:30:39.326Z" - }, - "retain_until":{ - "email":"2022-03-01T22:13:24.833Z" - }, - "meta":{ - "modified":"2022-11-08T04:09:20.828Z", - "first_sign_in":"2022-10-25T18:04:18.503Z", - "first_sign_in_method":"token_refresh", - "last_sign_in":"2022-11-09T02:55:19.464Z", - "last_sign_in_method":"token_refresh" - }, - "verified_data":{ - "email":"mhamann@rownd.io", - "phone_number":"+19192495211" - } - }) - ); - }), + rest.get( + 'https://mock-api.local/applications/290167281732813315/users/rownd-test-user-1/data', + (_, res, ctx) => { + return res( + ctx.json({ + data: { + email: 'juliet@rose.co', + user_id: 'rownd-test-user-1', + first_name: 'Juliet', + last_name: 'Rose', + phone_number: '+15555551212', + zip_code: '90210', + }, + redacted: ['zip_code'], + revoke_after: { + zip_code: '2022-08-15T16:30:39.326Z', + }, + retain_until: { + email: '2022-03-01T22:13:24.833Z', + }, + meta: { + modified: '2022-11-08T04:09:20.828Z', + first_sign_in: '2022-10-25T18:04:18.503Z', + first_sign_in_method: 'token_refresh', + last_sign_in: '2022-11-09T02:55:19.464Z', + last_sign_in_method: 'token_refresh', + }, + verified_data: { + email: 'mhamann@rownd.io', + phone_number: '+19192495211', + }, + }) + ); + } + ), + + rest.put( + 'https://mock-api.local/applications/290167281732813315/users/rownd-test-user-1/data', + (_, res, ctx) => { + return res( + ctx.json({ + data: { + email: 'testuser@rownd.app', + user_id: '71f6ceeb-ee0a-4437-9b44-e6229defbab8', + first_name: 'Juliet', + last_name: 'Rose', + phone_number: '+15555551212', + zip_code: '90210', + }, + redacted: ['zip_code'], + revoke_after: { + zip_code: '2022-08-15T16:30:39.326Z', + }, + retain_until: { + email: '2022-03-01T22:13:24.833Z', + }, + meta: { + modified: '2022-11-08T04:09:20.828Z', + first_sign_in: '2022-10-25T18:04:18.503Z', + first_sign_in_method: 'token_refresh', + last_sign_in: '2022-11-09T02:55:19.464Z', + last_sign_in_method: 'token_refresh', + }, + verified_data: { + email: 'mhamann@rownd.io', + phone_number: '+19192495211', + }, + }) + ); + } + ), - rest.post('https://mock-api.local/hub/auth/magic', (_, res, ctx) => { - return res( - ctx.json({ - link: 'https://mock-api.local/hub/auth/magic/complete', - app_user_id: 'test-app-user-1' - }) - ) - }), + rest.post('https://mock-api.local/hub/auth/magic', (_, res, ctx) => { + return res( + ctx.json({ + link: 'https://mock-api.local/hub/auth/magic/complete', + app_user_id: 'test-app-user-1', + }) + ); + }), ]; -export const server = setupServer(...handlers); \ No newline at end of file +export const server = setupServer(...handlers); From 41329a5ea91c321e976a4941d7cfbde59f9332d9 Mon Sep 17 00:00:00 2001 From: Matt Hamann Date: Wed, 9 Nov 2022 00:17:26 -0500 Subject: [PATCH 3/5] fix(api): prevent some calls from waiting forever --- README.md | 3 +++ src/lib/config.ts | 1 + src/lib/rownd.ts | 22 ++++++++++++++++++++-- src/types.d.ts | 2 +- 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 11290ae..c68a5cc 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,9 @@ Creates a new instance of the Rownd client. It requires the following object pro - `app_key` - Your Rownd application key. - `app_secret` - Your Rownd application secret. +Optionally, you can also pass in the following properties: +- `timeout` - The number of milliseconds to wait before timing out a request. Defaults to 10 seconds. If you're on a slow network and see any "Request timed out" errors, try increasing this value. + Example: ```js diff --git a/src/lib/config.ts b/src/lib/config.ts index 7bd1e60..855956d 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -4,6 +4,7 @@ const defaultConfig: TConfig = { api_url: 'https://api.rownd.io', app_key: process.env.ROWND_APP_KEY, app_secret: process.env.ROWND_APP_SECRET, + timeout: parseInt(process.env.ROWND_TIMEOUT || '10000', 10), }; export function createConfig(opts: Partial = {}): TConfig { diff --git a/src/lib/rownd.ts b/src/lib/rownd.ts index fd1c735..cf9e938 100644 --- a/src/lib/rownd.ts +++ b/src/lib/rownd.ts @@ -59,7 +59,16 @@ export class RowndInstance implements IRowndClient { } async fetchUserInfo(opts: FetchUserInfoOpts) { - await this.initPromise; // Ensure we have the app config before fetching user info. + // Ensure we have the app config before fetching user info. + await Promise.race([ + this.initPromise, + new Promise((_, reject) => + setTimeout( + () => reject(new Error('Request timed out')), + this.config.timeout + ) + ), + ]); let appId = opts?.app_id || this.config._app?.id; @@ -92,7 +101,16 @@ export class RowndInstance implements IRowndClient { } async createOrUpdateUser(user: RowndUser) { - await this.initPromise; // Ensure we have the app config before fetching user info. + // Ensure we have the app config before fetching user info, but don't wait forever + await Promise.race([ + this.initPromise, + new Promise((_, reject) => + setTimeout( + () => reject(new Error('Request timed out')), + this.config.timeout + ) + ), + ]); let resp: RowndUser = await got .put( diff --git a/src/types.d.ts b/src/types.d.ts index c5c4120..37f393b 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -2,7 +2,7 @@ export type TConfig = { api_url: string; app_key?: string; app_secret?: string; - app_id?: string; + timeout?: number; _app?: TApp; }; From 68672e8f92d82533df026c54758252ba63558d5e Mon Sep 17 00:00:00 2001 From: Matt Hamann Date: Wed, 9 Nov 2022 00:59:26 -0500 Subject: [PATCH 4/5] fix(express): tweaks supporting new arch --- examples/express/server.js | 4 +++- src/express/index.ts | 8 +++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/examples/express/server.js b/examples/express/server.js index 0acf788..addac03 100644 --- a/examples/express/server.js +++ b/examples/express/server.js @@ -1,8 +1,10 @@ const express = require('express'); -const { rownd } = require('../../'); +const Rownd = require('../../'); const app = express(); +const rownd = Rownd.createInstance(); + const { authenticate } = rownd.express; app.get('/', (req, res) => { diff --git a/src/express/index.ts b/src/express/index.ts index e4499d1..002d4e4 100644 --- a/src/express/index.ts +++ b/src/express/index.ts @@ -22,9 +22,10 @@ export class RowndExpressClient implements IRowndExpressClient { constructor(rownd: RowndInstance) { this.rownd = rownd; + this.authenticate = this.authenticate.bind(this); // Hack to allow safe destructuring } - public authenticate(opts: AuthenticateOpts) { + authenticate (opts: AuthenticateOpts) { opts = { fetchUserInfo: false, errOnInvalidToken: true, @@ -36,6 +37,7 @@ export class RowndExpressClient implements IRowndExpressClient { _: express.Response, next: express.NextFunction ) => { + const plugin = this; req.authenticated = req.isAuthenticated = false; let authHeader = req.get('authorization'); authHeader = authHeader?.replace(/^bearer /i, ''); @@ -54,12 +56,12 @@ export class RowndExpressClient implements IRowndExpressClient { next: express.NextFunction ) => { try { - let tokenInfo = await this.rownd.validateToken(authHeader); + let tokenInfo = await plugin.rownd.validateToken(authHeader); req.tokenInfo = tokenInfo; req.authenticated = req.isAuthenticated = true; if (opts.fetchUserInfo) { - let userInfo = await this.rownd.fetchUserInfo({ + let userInfo = await plugin.rownd.fetchUserInfo({ user_id: tokenInfo.user_id, }); req.user = userInfo.data; From 4fd849befef5447f2e67513507fd5eb6395ebb5c Mon Sep 17 00:00:00 2001 From: Matt Hamann Date: Wed, 9 Nov 2022 01:01:29 -0500 Subject: [PATCH 5/5] chore: lint fixes --- src/express/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/express/index.ts b/src/express/index.ts index 002d4e4..4e8aa31 100644 --- a/src/express/index.ts +++ b/src/express/index.ts @@ -25,7 +25,7 @@ export class RowndExpressClient implements IRowndExpressClient { this.authenticate = this.authenticate.bind(this); // Hack to allow safe destructuring } - authenticate (opts: AuthenticateOpts) { + authenticate(opts: AuthenticateOpts) { opts = { fetchUserInfo: false, errOnInvalidToken: true,