From 84a2d4b9fa271c2ba3bc8e80db059187e3b49323 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 8 Mar 2024 10:47:32 +0100 Subject: [PATCH 01/58] Upgrade TypeScript --- package.json | 2 +- pnpm-lock.yaml | 90 +++++++++++++++++++++++++------------------------- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/package.json b/package.json index c2a641cc..7e7cae2b 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "react-dom": "18.2.0", "tsm": "^2.2.2", "tsup": "^6.2.3", - "typescript": "4.9.5", + "typescript": "5.4.2", "vi-fetch": "^0.8.0", "vite": "^4.0.4", "vitest": "^0.28.1" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 412d3491..43b35be3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,5 +1,9 @@ lockfileVersion: '6.0' +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + dependencies: '@opentelemetry/api': specifier: ^1.7.0 @@ -50,10 +54,10 @@ devDependencies: version: 8.3.4 '@typescript-eslint/eslint-plugin': specifier: ^5.36.1 - version: 5.36.1(@typescript-eslint/parser@5.36.1)(eslint@8.23.0)(typescript@4.9.5) + version: 5.36.1(@typescript-eslint/parser@5.36.1)(eslint@8.23.0)(typescript@5.4.2) '@typescript-eslint/parser': specifier: ^5.36.1 - version: 5.36.1(eslint@8.23.0)(typescript@4.9.5) + version: 5.36.1(eslint@8.23.0)(typescript@5.4.2) '@vercel/kv': specifier: 1.0.0 version: 1.0.0 @@ -128,10 +132,10 @@ devDependencies: version: 2.2.2 tsup: specifier: ^6.2.3 - version: 6.2.3(typescript@4.9.5) + version: 6.2.3(typescript@5.4.2) typescript: - specifier: 4.9.5 - version: 4.9.5 + specifier: 5.4.2 + version: 5.4.2 vi-fetch: specifier: ^0.8.0 version: 0.8.0 @@ -1195,7 +1199,7 @@ packages: resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==} dev: true - /@typescript-eslint/eslint-plugin@5.36.1(@typescript-eslint/parser@5.36.1)(eslint@8.23.0)(typescript@4.9.5): + /@typescript-eslint/eslint-plugin@5.36.1(@typescript-eslint/parser@5.36.1)(eslint@8.23.0)(typescript@5.4.2): resolution: {integrity: sha512-iC40UK8q1tMepSDwiLbTbMXKDxzNy+4TfPWgIL661Ym0sD42vRcQU93IsZIrmi+x292DBr60UI/gSwfdVYexCA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -1206,23 +1210,23 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/parser': 5.36.1(eslint@8.23.0)(typescript@4.9.5) + '@typescript-eslint/parser': 5.36.1(eslint@8.23.0)(typescript@5.4.2) '@typescript-eslint/scope-manager': 5.36.1 - '@typescript-eslint/type-utils': 5.36.1(eslint@8.23.0)(typescript@4.9.5) - '@typescript-eslint/utils': 5.36.1(eslint@8.23.0)(typescript@4.9.5) + '@typescript-eslint/type-utils': 5.36.1(eslint@8.23.0)(typescript@5.4.2) + '@typescript-eslint/utils': 5.36.1(eslint@8.23.0)(typescript@5.4.2) debug: 4.3.4 eslint: 8.23.0 functional-red-black-tree: 1.0.1 ignore: 5.2.0 regexpp: 3.2.0 semver: 7.5.4 - tsutils: 3.21.0(typescript@4.9.5) - typescript: 4.9.5 + tsutils: 3.21.0(typescript@5.4.2) + typescript: 5.4.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@5.36.1(eslint@8.23.0)(typescript@4.9.5): + /@typescript-eslint/parser@5.36.1(eslint@8.23.0)(typescript@5.4.2): resolution: {integrity: sha512-/IsgNGOkBi7CuDfUbwt1eOqUXF9WGVBW9dwEe1pi+L32XrTsZIgmDFIi2RxjzsvB/8i+MIf5JIoTEH8LOZ368A==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -1234,10 +1238,10 @@ packages: dependencies: '@typescript-eslint/scope-manager': 5.36.1 '@typescript-eslint/types': 5.36.1 - '@typescript-eslint/typescript-estree': 5.36.1(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 5.36.1(typescript@5.4.2) debug: 4.3.4 eslint: 8.23.0 - typescript: 4.9.5 + typescript: 5.4.2 transitivePeerDependencies: - supports-color dev: true @@ -1250,7 +1254,7 @@ packages: '@typescript-eslint/visitor-keys': 5.36.1 dev: true - /@typescript-eslint/type-utils@5.36.1(eslint@8.23.0)(typescript@4.9.5): + /@typescript-eslint/type-utils@5.36.1(eslint@8.23.0)(typescript@5.4.2): resolution: {integrity: sha512-xfZhfmoQT6m3lmlqDvDzv9TiCYdw22cdj06xY0obSznBsT///GK5IEZQdGliXpAOaRL34o8phEvXzEo/VJx13Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -1260,12 +1264,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 5.36.1(typescript@4.9.5) - '@typescript-eslint/utils': 5.36.1(eslint@8.23.0)(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 5.36.1(typescript@5.4.2) + '@typescript-eslint/utils': 5.36.1(eslint@8.23.0)(typescript@5.4.2) debug: 4.3.4 eslint: 8.23.0 - tsutils: 3.21.0(typescript@4.9.5) - typescript: 4.9.5 + tsutils: 3.21.0(typescript@5.4.2) + typescript: 5.4.2 transitivePeerDependencies: - supports-color dev: true @@ -1275,7 +1279,7 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/typescript-estree@5.36.1(typescript@4.9.5): + /@typescript-eslint/typescript-estree@5.36.1(typescript@5.4.2): resolution: {integrity: sha512-ih7V52zvHdiX6WcPjsOdmADhYMDN15SylWRZrT2OMy80wzKbc79n8wFW0xpWpU0x3VpBz/oDgTm2xwDAnFTl+g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -1290,13 +1294,13 @@ packages: globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.4 - tsutils: 3.21.0(typescript@4.9.5) - typescript: 4.9.5 + tsutils: 3.21.0(typescript@5.4.2) + typescript: 5.4.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@5.36.1(eslint@8.23.0)(typescript@4.9.5): + /@typescript-eslint/utils@5.36.1(eslint@8.23.0)(typescript@5.4.2): resolution: {integrity: sha512-lNj4FtTiXm5c+u0pUehozaUWhh7UYKnwryku0nxJlYUEWetyG92uw2pr+2Iy4M/u0ONMKzfrx7AsGBTCzORmIg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -1305,7 +1309,7 @@ packages: '@types/json-schema': 7.0.11 '@typescript-eslint/scope-manager': 5.36.1 '@typescript-eslint/types': 5.36.1 - '@typescript-eslint/typescript-estree': 5.36.1(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 5.36.1(typescript@5.4.2) eslint: 8.23.0 eslint-scope: 5.1.1 eslint-utils: 3.0.0(eslint@8.23.0) @@ -1791,7 +1795,7 @@ packages: normalize-path: 3.0.0 readdirp: 3.6.0 optionalDependencies: - fsevents: 2.3.2 + fsevents: 2.3.3 dev: true /ci-info@3.9.0: @@ -2738,8 +2742,8 @@ packages: eslint: ^7.32.0 || ^8.2.0 eslint-plugin-import: ^2.25.3 dependencies: - '@typescript-eslint/eslint-plugin': 5.36.1(@typescript-eslint/parser@5.36.1)(eslint@8.23.0)(typescript@4.9.5) - '@typescript-eslint/parser': 5.36.1(eslint@8.23.0)(typescript@4.9.5) + '@typescript-eslint/eslint-plugin': 5.36.1(@typescript-eslint/parser@5.36.1)(eslint@8.23.0)(typescript@5.4.2) + '@typescript-eslint/parser': 5.36.1(eslint@8.23.0)(typescript@5.4.2) eslint: 8.23.0 eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.26.0)(eslint@8.23.0) eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.36.1)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0) @@ -2824,7 +2828,7 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.36.1(eslint@8.23.0)(typescript@4.9.5) + '@typescript-eslint/parser': 5.36.1(eslint@8.23.0)(typescript@5.4.2) debug: 3.2.7 eslint: 8.23.0 eslint-import-resolver-node: 0.3.6 @@ -2843,7 +2847,7 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.36.1(eslint@8.23.0)(typescript@4.9.5) + '@typescript-eslint/parser': 5.36.1(eslint@8.23.0)(typescript@5.4.2) array-includes: 3.1.5 array.prototype.flat: 1.3.0 debug: 2.6.9 @@ -3224,8 +3228,8 @@ packages: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} dev: true - /fsevents@2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + /fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] requiresBuild: true @@ -4909,7 +4913,7 @@ packages: engines: {node: '>=10.0.0'} hasBin: true optionalDependencies: - fsevents: 2.3.2 + fsevents: 2.3.3 dev: true /rollup@3.10.1: @@ -4917,7 +4921,7 @@ packages: engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true optionalDependencies: - fsevents: 2.3.2 + fsevents: 2.3.3 dev: true /run-parallel@1.2.0: @@ -5470,7 +5474,7 @@ packages: esbuild: 0.14.54 dev: true - /tsup@6.2.3(typescript@4.9.5): + /tsup@6.2.3(typescript@5.4.2): resolution: {integrity: sha512-J5Pu2Dx0E1wlpIEsVFv9ryzP1pZ1OYsJ2cBHZ7GrKteytNdzaSz5hmLX7/nAxtypq+jVkVvA79d7S83ETgHQ5w==} engines: {node: '>=14'} hasBin: true @@ -5500,20 +5504,20 @@ packages: source-map: 0.8.0-beta.0 sucrase: 3.25.0 tree-kill: 1.2.2 - typescript: 4.9.5 + typescript: 5.4.2 transitivePeerDependencies: - supports-color - ts-node dev: true - /tsutils@3.21.0(typescript@4.9.5): + /tsutils@3.21.0(typescript@5.4.2): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' dependencies: tslib: 1.14.1 - typescript: 4.9.5 + typescript: 5.4.2 dev: true /tty-table@4.1.6: @@ -5582,9 +5586,9 @@ packages: mime-types: 2.1.35 dev: true - /typescript@4.9.5: - resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} - engines: {node: '>=4.2.0'} + /typescript@5.4.2: + resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==} + engines: {node: '>=14.17'} hasBin: true dev: true @@ -5753,7 +5757,7 @@ packages: resolve: 1.22.1 rollup: 3.10.1 optionalDependencies: - fsevents: 2.3.2 + fsevents: 2.3.3 dev: true /vitest@0.27.2(jsdom@20.0.3): @@ -6114,7 +6118,3 @@ packages: dev: false publishDirectory: dist - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false From 7e1ca8542605136234f9233b4a24e71e7e0d0ce8 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 8 Mar 2024 10:52:19 +0100 Subject: [PATCH 02/58] Upgrade TS ESlint parser --- package.json | 2 +- pnpm-lock.yaml | 131 +++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 106 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index 7e7cae2b..0ecb3b6b 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@types/react-dom": "^18.0.5", "@types/uuid": "^8.3.4", "@typescript-eslint/eslint-plugin": "^5.36.1", - "@typescript-eslint/parser": "^5.36.1", + "@typescript-eslint/parser": "^7.1.1", "@vercel/kv": "1.0.0", "@vitejs/plugin-react": "^3.0.1", "@vitest/coverage-c8": "^0.27.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 43b35be3..9099d60e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -54,10 +54,10 @@ devDependencies: version: 8.3.4 '@typescript-eslint/eslint-plugin': specifier: ^5.36.1 - version: 5.36.1(@typescript-eslint/parser@5.36.1)(eslint@8.23.0)(typescript@5.4.2) + version: 5.36.1(@typescript-eslint/parser@7.1.1)(eslint@8.23.0)(typescript@5.4.2) '@typescript-eslint/parser': - specifier: ^5.36.1 - version: 5.36.1(eslint@8.23.0)(typescript@5.4.2) + specifier: ^7.1.1 + version: 7.1.1(eslint@8.23.0)(typescript@5.4.2) '@vercel/kv': specifier: 1.0.0 version: 1.0.0 @@ -78,7 +78,7 @@ devDependencies: version: 19.0.4(eslint-plugin-import@2.26.0)(eslint-plugin-jsx-a11y@6.6.1)(eslint-plugin-react-hooks@4.6.0)(eslint-plugin-react@7.31.6)(eslint@8.23.0) eslint-config-airbnb-typescript: specifier: ^17.1.0 - version: 17.1.0(@typescript-eslint/eslint-plugin@5.36.1)(@typescript-eslint/parser@5.36.1)(eslint-plugin-import@2.26.0)(eslint@8.23.0) + version: 17.1.0(@typescript-eslint/eslint-plugin@5.36.1)(@typescript-eslint/parser@7.1.1)(eslint-plugin-import@2.26.0)(eslint@8.23.0) eslint-config-prettier: specifier: ^8.5.0 version: 8.5.0(eslint@8.23.0) @@ -87,7 +87,7 @@ devDependencies: version: 3.5.0(eslint-plugin-import@2.26.0)(eslint@8.23.0) eslint-plugin-import: specifier: ^2.26.0 - version: 2.26.0(@typescript-eslint/parser@5.36.1)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0) + version: 2.26.0(@typescript-eslint/parser@7.1.1)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0) eslint-plugin-jsx-a11y: specifier: ^6.6.1 version: 6.6.1(eslint@8.23.0) @@ -1199,7 +1199,7 @@ packages: resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==} dev: true - /@typescript-eslint/eslint-plugin@5.36.1(@typescript-eslint/parser@5.36.1)(eslint@8.23.0)(typescript@5.4.2): + /@typescript-eslint/eslint-plugin@5.36.1(@typescript-eslint/parser@7.1.1)(eslint@8.23.0)(typescript@5.4.2): resolution: {integrity: sha512-iC40UK8q1tMepSDwiLbTbMXKDxzNy+4TfPWgIL661Ym0sD42vRcQU93IsZIrmi+x292DBr60UI/gSwfdVYexCA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -1210,7 +1210,7 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/parser': 5.36.1(eslint@8.23.0)(typescript@5.4.2) + '@typescript-eslint/parser': 7.1.1(eslint@8.23.0)(typescript@5.4.2) '@typescript-eslint/scope-manager': 5.36.1 '@typescript-eslint/type-utils': 5.36.1(eslint@8.23.0)(typescript@5.4.2) '@typescript-eslint/utils': 5.36.1(eslint@8.23.0)(typescript@5.4.2) @@ -1226,19 +1226,20 @@ packages: - supports-color dev: true - /@typescript-eslint/parser@5.36.1(eslint@8.23.0)(typescript@5.4.2): - resolution: {integrity: sha512-/IsgNGOkBi7CuDfUbwt1eOqUXF9WGVBW9dwEe1pi+L32XrTsZIgmDFIi2RxjzsvB/8i+MIf5JIoTEH8LOZ368A==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/parser@7.1.1(eslint@8.23.0)(typescript@5.4.2): + resolution: {integrity: sha512-ZWUFyL0z04R1nAEgr9e79YtV5LbafdOtN7yapNbn1ansMyaegl2D4bL7vHoJ4HPSc4CaLwuCVas8CVuneKzplQ==} + engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + eslint: ^8.56.0 typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 5.36.1 - '@typescript-eslint/types': 5.36.1 - '@typescript-eslint/typescript-estree': 5.36.1(typescript@5.4.2) + '@typescript-eslint/scope-manager': 7.1.1 + '@typescript-eslint/types': 7.1.1 + '@typescript-eslint/typescript-estree': 7.1.1(typescript@5.4.2) + '@typescript-eslint/visitor-keys': 7.1.1 debug: 4.3.4 eslint: 8.23.0 typescript: 5.4.2 @@ -1254,6 +1255,14 @@ packages: '@typescript-eslint/visitor-keys': 5.36.1 dev: true + /@typescript-eslint/scope-manager@7.1.1: + resolution: {integrity: sha512-cirZpA8bJMRb4WZ+rO6+mnOJrGFDd38WoXCEI57+CYBqta8Yc8aJym2i7vyqLL1vVYljgw0X27axkUXz32T8TA==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 7.1.1 + '@typescript-eslint/visitor-keys': 7.1.1 + dev: true + /@typescript-eslint/type-utils@5.36.1(eslint@8.23.0)(typescript@5.4.2): resolution: {integrity: sha512-xfZhfmoQT6m3lmlqDvDzv9TiCYdw22cdj06xY0obSznBsT///GK5IEZQdGliXpAOaRL34o8phEvXzEo/VJx13Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1279,6 +1288,11 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true + /@typescript-eslint/types@7.1.1: + resolution: {integrity: sha512-KhewzrlRMrgeKm1U9bh2z5aoL4s7K3tK5DwHDn8MHv0yQfWFz/0ZR6trrIHHa5CsF83j/GgHqzdbzCXJ3crx0Q==} + engines: {node: ^16.0.0 || >=18.0.0} + dev: true + /@typescript-eslint/typescript-estree@5.36.1(typescript@5.4.2): resolution: {integrity: sha512-ih7V52zvHdiX6WcPjsOdmADhYMDN15SylWRZrT2OMy80wzKbc79n8wFW0xpWpU0x3VpBz/oDgTm2xwDAnFTl+g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1300,6 +1314,28 @@ packages: - supports-color dev: true + /@typescript-eslint/typescript-estree@7.1.1(typescript@5.4.2): + resolution: {integrity: sha512-9ZOncVSfr+sMXVxxca2OJOPagRwT0u/UHikM2Rd6L/aB+kL/QAuTnsv6MeXtjzCJYb8PzrXarypSGIPx3Jemxw==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 7.1.1 + '@typescript-eslint/visitor-keys': 7.1.1 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + minimatch: 9.0.3 + semver: 7.6.0 + ts-api-utils: 1.2.1(typescript@5.4.2) + typescript: 5.4.2 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/utils@5.36.1(eslint@8.23.0)(typescript@5.4.2): resolution: {integrity: sha512-lNj4FtTiXm5c+u0pUehozaUWhh7UYKnwryku0nxJlYUEWetyG92uw2pr+2Iy4M/u0ONMKzfrx7AsGBTCzORmIg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1326,6 +1362,14 @@ packages: eslint-visitor-keys: 3.3.0 dev: true + /@typescript-eslint/visitor-keys@7.1.1: + resolution: {integrity: sha512-yTdHDQxY7cSoCcAtiBzVzxleJhkGB9NncSIyMYe2+OGON1ZsP9zOPws/Pqgopa65jvknOjlk/w7ulPlZ78PiLQ==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 7.1.1 + eslint-visitor-keys: 3.4.3 + dev: true + /@upstash/redis@1.24.3: resolution: {integrity: sha512-gw6d4IA1biB4eye5ESaXc0zOlVQI94aptsBvVcTghYWu1kRmOrJFoMFEDCa8p5uzluyYAOFCuY2GWLR6O4ZoIw==} dependencies: @@ -1641,6 +1685,12 @@ packages: concat-map: 0.0.1 dev: true + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + dev: true + /braces@3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} engines: {node: '>=8'} @@ -2728,13 +2778,13 @@ packages: dependencies: confusing-browser-globals: 1.0.11 eslint: 8.23.0 - eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.36.1)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0) + eslint-plugin-import: 2.26.0(@typescript-eslint/parser@7.1.1)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0) object.assign: 4.1.4 object.entries: 1.1.5 semver: 6.3.0 dev: true - /eslint-config-airbnb-typescript@17.1.0(@typescript-eslint/eslint-plugin@5.36.1)(@typescript-eslint/parser@5.36.1)(eslint-plugin-import@2.26.0)(eslint@8.23.0): + /eslint-config-airbnb-typescript@17.1.0(@typescript-eslint/eslint-plugin@5.36.1)(@typescript-eslint/parser@7.1.1)(eslint-plugin-import@2.26.0)(eslint@8.23.0): resolution: {integrity: sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig==} peerDependencies: '@typescript-eslint/eslint-plugin': ^5.13.0 || ^6.0.0 @@ -2742,11 +2792,11 @@ packages: eslint: ^7.32.0 || ^8.2.0 eslint-plugin-import: ^2.25.3 dependencies: - '@typescript-eslint/eslint-plugin': 5.36.1(@typescript-eslint/parser@5.36.1)(eslint@8.23.0)(typescript@5.4.2) - '@typescript-eslint/parser': 5.36.1(eslint@8.23.0)(typescript@5.4.2) + '@typescript-eslint/eslint-plugin': 5.36.1(@typescript-eslint/parser@7.1.1)(eslint@8.23.0)(typescript@5.4.2) + '@typescript-eslint/parser': 7.1.1(eslint@8.23.0)(typescript@5.4.2) eslint: 8.23.0 eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.26.0)(eslint@8.23.0) - eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.36.1)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0) + eslint-plugin-import: 2.26.0(@typescript-eslint/parser@7.1.1)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0) dev: true /eslint-config-airbnb@19.0.4(eslint-plugin-import@2.26.0)(eslint-plugin-jsx-a11y@6.6.1)(eslint-plugin-react-hooks@4.6.0)(eslint-plugin-react@7.31.6)(eslint@8.23.0): @@ -2761,7 +2811,7 @@ packages: dependencies: eslint: 8.23.0 eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.26.0)(eslint@8.23.0) - eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.36.1)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0) + eslint-plugin-import: 2.26.0(@typescript-eslint/parser@7.1.1)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0) eslint-plugin-jsx-a11y: 6.6.1(eslint@8.23.0) eslint-plugin-react: 7.31.6(eslint@8.23.0) eslint-plugin-react-hooks: 4.6.0(eslint@8.23.0) @@ -2797,7 +2847,7 @@ packages: debug: 4.3.4 enhanced-resolve: 5.10.0 eslint: 8.23.0 - eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.36.1)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0) + eslint-plugin-import: 2.26.0(@typescript-eslint/parser@7.1.1)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0) get-tsconfig: 4.2.0 globby: 13.1.2 is-core-module: 2.10.0 @@ -2807,7 +2857,7 @@ packages: - supports-color dev: true - /eslint-module-utils@2.7.4(@typescript-eslint/parser@5.36.1)(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0): + /eslint-module-utils@2.7.4(@typescript-eslint/parser@7.1.1)(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0): resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} engines: {node: '>=4'} peerDependencies: @@ -2828,7 +2878,7 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.36.1(eslint@8.23.0)(typescript@5.4.2) + '@typescript-eslint/parser': 7.1.1(eslint@8.23.0)(typescript@5.4.2) debug: 3.2.7 eslint: 8.23.0 eslint-import-resolver-node: 0.3.6 @@ -2837,7 +2887,7 @@ packages: - supports-color dev: true - /eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.36.1)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0): + /eslint-plugin-import@2.26.0(@typescript-eslint/parser@7.1.1)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0): resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} engines: {node: '>=4'} peerDependencies: @@ -2847,14 +2897,14 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.36.1(eslint@8.23.0)(typescript@5.4.2) + '@typescript-eslint/parser': 7.1.1(eslint@8.23.0)(typescript@5.4.2) array-includes: 3.1.5 array.prototype.flat: 1.3.0 debug: 2.6.9 doctrine: 2.1.0 eslint: 8.23.0 eslint-import-resolver-node: 0.3.6 - eslint-module-utils: 2.7.4(@typescript-eslint/parser@5.36.1)(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0) + eslint-module-utils: 2.7.4(@typescript-eslint/parser@7.1.1)(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0) has: 1.0.3 is-core-module: 2.10.0 is-glob: 4.0.3 @@ -2966,6 +3016,11 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true + /eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + /eslint@8.23.0: resolution: {integrity: sha512-pBG/XOn0MsJcKcTRLr27S5HpzQo4kLr+HjLQIyK4EiCsijDl/TB+h5uEuJU6bQ8Edvwz1XWOjpaP2qgnXGpTcA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -4162,6 +4217,13 @@ packages: brace-expansion: 1.1.11 dev: true + /minimatch@9.0.3: + resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + dev: true + /minimist-options@4.1.0: resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} engines: {node: '>= 6'} @@ -4978,6 +5040,14 @@ packages: lru-cache: 6.0.0 dev: true + /semver@7.6.0: + resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + /set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} dev: true @@ -5445,6 +5515,15 @@ packages: engines: {node: '>=8'} dev: true + /ts-api-utils@1.2.1(typescript@5.4.2): + resolution: {integrity: sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' + dependencies: + typescript: 5.4.2 + dev: true + /ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} dev: true From 6ca0c678804d386131836cf16fc4e4e06b7b2b54 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 8 Mar 2024 10:52:30 +0100 Subject: [PATCH 03/58] Add manifest handler for Edge Runtime --- .../next-edge/create-manifest-handler.ts | 25 +++++++++++++++++++ src/headers.ts | 23 +++++++++++++++-- 2 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 src/handlers/next-edge/create-manifest-handler.ts diff --git a/src/handlers/next-edge/create-manifest-handler.ts b/src/handlers/next-edge/create-manifest-handler.ts new file mode 100644 index 00000000..22f28a85 --- /dev/null +++ b/src/handlers/next-edge/create-manifest-handler.ts @@ -0,0 +1,25 @@ +import { getBaseUrlFetchAPI, getSaleorHeadersFetchAPI } from "../../headers"; +import { AppManifest } from "../../types"; + +export type CreateManifestHandlerOptions = { + manifestFactory(context: { + appBaseUrl: string; + request: Request; + /** For Saleor < 3.15 it will be null. */ + schemaVersion: number | null; + }): AppManifest | Promise; +}; + +export const createManifestHandler = + (options: CreateManifestHandlerOptions) => async (request: Request) => { + const { schemaVersion } = getSaleorHeadersFetchAPI(request.headers); + const baseURL = getBaseUrlFetchAPI(request.headers); + + const manifest = await options.manifestFactory({ + appBaseUrl: baseURL, + request, + schemaVersion, + }); + + return Response.json(manifest); + }; diff --git a/src/headers.ts b/src/headers.ts index e5fc701b..0bcec654 100644 --- a/src/headers.ts +++ b/src/headers.ts @@ -7,10 +7,10 @@ import { SALEOR_SIGNATURE_HEADER, } from "./const"; -const toStringOrUndefined = (value: string | string[] | undefined) => +const toStringOrUndefined = (value: string | string[] | undefined | null) => value ? value.toString() : undefined; -const toFloatOrNull = (value: string | string[] | undefined) => +const toFloatOrNull = (value: string | string[] | undefined | null) => value ? parseFloat(value.toString()) : null; /** @@ -25,6 +25,15 @@ export const getSaleorHeaders = (headers: { [name: string]: string | string[] | schemaVersion: toFloatOrNull(headers[SALEOR_SCHEMA_VERSION]), }); +export const getSaleorHeadersFetchAPI = (headers: Headers) => ({ + domain: toStringOrUndefined(headers.get(SALEOR_DOMAIN_HEADER)), + authorizationBearer: toStringOrUndefined(headers.get(SALEOR_AUTHORIZATION_BEARER_HEADER)), + signature: toStringOrUndefined(headers.get(SALEOR_SIGNATURE_HEADER)), + event: toStringOrUndefined(headers.get(SALEOR_EVENT_HEADER)), + saleorApiUrl: toStringOrUndefined(headers.get(SALEOR_API_URL_HEADER)), + schemaVersion: toFloatOrNull(headers.get(SALEOR_SCHEMA_VERSION)), +}); + /** * Extracts the app's url from headers from the response. */ @@ -40,3 +49,13 @@ export const getBaseUrl = (headers: { [name: string]: string | string[] | undefi return `${protocol}://${host}`; }; + +export const getBaseUrlFetchAPI = (headers: Headers) => { + const host = headers.get("host"); + const xForwardedProto = headers.get("x-forwarded-proto") || "http"; + + const protocols = xForwardedProto.split(",").map((value) => value.trimStart()); + const protocol = protocols.find((el) => el === "https") || protocols[0]; + + return `${protocol}://${host}`; +}; From 37fd7314d4feb34f8ee183aabcf940aea7576481 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 8 Mar 2024 10:54:09 +0100 Subject: [PATCH 04/58] Fix TS errors --- src/APL/vercel-kv/vercel-kv-apl.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/APL/vercel-kv/vercel-kv-apl.ts b/src/APL/vercel-kv/vercel-kv-apl.ts index bab2ad16..2880c08c 100644 --- a/src/APL/vercel-kv/vercel-kv-apl.ts +++ b/src/APL/vercel-kv/vercel-kv-apl.ts @@ -55,7 +55,7 @@ export class VercelKvApl implements APL { span .setStatus({ - code: 200, + code: SpanStatusCode.OK, message: "Received response from VercelKV", }) .end(); @@ -101,7 +101,7 @@ export class VercelKvApl implements APL { span .setStatus({ - code: 200, + code: SpanStatusCode.OK, message: "Successfully written auth data to VercelKV", }) .end(); @@ -140,7 +140,7 @@ export class VercelKvApl implements APL { span .setStatus({ - code: 200, + code: SpanStatusCode.OK, message: "Successfully deleted auth data to VercelKV", }) .end(); From fa1164df9613d17ac875bc5e39dcad9619d113b8 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 8 Mar 2024 10:57:35 +0100 Subject: [PATCH 05/58] Add changeset --- .changeset/fluffy-cheetahs-sleep.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fluffy-cheetahs-sleep.md diff --git a/.changeset/fluffy-cheetahs-sleep.md b/.changeset/fluffy-cheetahs-sleep.md new file mode 100644 index 00000000..e7de93f0 --- /dev/null +++ b/.changeset/fluffy-cheetahs-sleep.md @@ -0,0 +1,5 @@ +--- +"@saleor/app-sdk": minor +--- + +Experimental: Added `handlers/next-edge` which adds support for Next.js Edge Runtime From 362c1f6a5bbaa3d193bdc64bc74bd306dc1e03c5 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 8 Mar 2024 11:00:37 +0100 Subject: [PATCH 06/58] Add default export --- src/handlers/next-edge/index.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/handlers/next-edge/index.ts diff --git a/src/handlers/next-edge/index.ts b/src/handlers/next-edge/index.ts new file mode 100644 index 00000000..037eb059 --- /dev/null +++ b/src/handlers/next-edge/index.ts @@ -0,0 +1 @@ +export * from "./create-manifest-handler"; From b2947b2c5eab962a91dc9832552a957b5c1e38a5 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 8 Mar 2024 11:10:15 +0100 Subject: [PATCH 07/58] Expose new folder --- package.json | 5 +++++ tsup.config.ts | 1 + 2 files changed, 6 insertions(+) diff --git a/package.json b/package.json index 0ecb3b6b..d277f17a 100644 --- a/package.json +++ b/package.json @@ -133,6 +133,11 @@ "import": "./handlers/next/index.mjs", "require": "./handlers/next/index.js" }, + "./handlers/next-edge": { + "types": "./handlers/next-edge/index.d.ts", + "import": "./handlers/next-edge/index.mjs", + "require": "./handlers/next-edge/index.js" + }, "./saleor-app": { "types": "./saleor-app.d.ts", "import": "./saleor-app.mjs", diff --git a/tsup.config.ts b/tsup.config.ts index 720a028e..5d26e0be 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -14,6 +14,7 @@ export default defineConfig({ "src/app-bridge/index.ts", "src/app-bridge/next/index.ts", "src/handlers/next/index.ts", + "src/handlers/next-edge/index.ts", "src/middleware/index.ts", "src/settings-manager/index.ts", ], From eca691164f869e4ca50c449f6ca8d5b53658b264 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 8 Mar 2024 12:54:27 +0100 Subject: [PATCH 08/58] Add middlewares for FetchAPI, add Edge register handler --- package.json | 5 + src/fetch-middleware/index.ts | 6 + src/fetch-middleware/middleware-debug.ts | 4 + src/fetch-middleware/to-next-edge-handler.ts | 20 ++ src/fetch-middleware/types.ts | 5 + .../with-auth-token-required.ts | 32 ++ src/fetch-middleware/with-method.ts | 25 ++ .../with-registered-saleor-domain-header.ts | 51 +++ src/fetch-middleware/with-saleor-app.ts | 20 ++ .../with-saleor-domain-present.ts | 25 ++ .../next-edge/create-app-register-handler.ts | 301 ++++++++++++++++++ src/handlers/next-edge/index.ts | 1 + tsup.config.ts | 1 + 13 files changed, 496 insertions(+) create mode 100644 src/fetch-middleware/index.ts create mode 100644 src/fetch-middleware/middleware-debug.ts create mode 100644 src/fetch-middleware/to-next-edge-handler.ts create mode 100644 src/fetch-middleware/types.ts create mode 100644 src/fetch-middleware/with-auth-token-required.ts create mode 100644 src/fetch-middleware/with-method.ts create mode 100644 src/fetch-middleware/with-registered-saleor-domain-header.ts create mode 100644 src/fetch-middleware/with-saleor-app.ts create mode 100644 src/fetch-middleware/with-saleor-domain-present.ts create mode 100644 src/handlers/next-edge/create-app-register-handler.ts diff --git a/package.json b/package.json index d277f17a..12ffa985 100644 --- a/package.json +++ b/package.json @@ -108,6 +108,11 @@ "import": "./settings-manager/index.mjs", "require": "./settings-manager/index.js" }, + "./fetch-middleware": { + "types": "./fetch-middleware/index.d.ts", + "import": "./fetch-middleware/index.mjs", + "require": "./fetch-middleware/index.js" + }, "./middleware": { "types": "./middleware/index.d.ts", "import": "./middleware/index.mjs", diff --git a/src/fetch-middleware/index.ts b/src/fetch-middleware/index.ts new file mode 100644 index 00000000..b0e4eef1 --- /dev/null +++ b/src/fetch-middleware/index.ts @@ -0,0 +1,6 @@ +export * from "./to-next-edge-handler"; +export * from "./with-auth-token-required"; +export * from "./with-method"; +export * from "./with-registered-saleor-domain-header"; +export * from "./with-saleor-app"; +export * from "./with-saleor-domain-present"; diff --git a/src/fetch-middleware/middleware-debug.ts b/src/fetch-middleware/middleware-debug.ts new file mode 100644 index 00000000..8ae78f70 --- /dev/null +++ b/src/fetch-middleware/middleware-debug.ts @@ -0,0 +1,4 @@ +import { createDebug } from "../debug"; + +export const createFetchMiddlewareDebug = (middleware: string) => + createDebug(`FetchMiddleware:${middleware}`); diff --git a/src/fetch-middleware/to-next-edge-handler.ts b/src/fetch-middleware/to-next-edge-handler.ts new file mode 100644 index 00000000..df35a3d6 --- /dev/null +++ b/src/fetch-middleware/to-next-edge-handler.ts @@ -0,0 +1,20 @@ +import { FetchHandler, FetchPipeline, ReveredFetchPipeline } from "./types"; + +const isPipeline = (maybePipeline: unknown): maybePipeline is FetchPipeline => + Array.isArray(maybePipeline); + +const compose = + (...functions: T[]) => + (args: any) => + functions.reduce((arg, fn) => fn(arg), args); + +const preparePipeline = (pipeline: FetchPipeline): FetchHandler => { + const [action, ...middleware] = pipeline.reverse() as ReveredFetchPipeline; + return compose(...middleware)(action); +}; + +export const toNextEdgeHandler = (flow: FetchHandler | FetchPipeline): FetchHandler => { + const handler = isPipeline(flow) ? preparePipeline(flow) : flow; + + return async (request: Request) => handler(request); +}; diff --git a/src/fetch-middleware/types.ts b/src/fetch-middleware/types.ts new file mode 100644 index 00000000..0cdca82d --- /dev/null +++ b/src/fetch-middleware/types.ts @@ -0,0 +1,5 @@ +export type SaleorRequest = Request & { context?: Record }; +export type FetchHandler = (req: SaleorRequest) => Response | Promise; +export type FetchMiddleware = (handler: FetchHandler) => FetchHandler; +export type FetchPipeline = [...FetchMiddleware[], FetchHandler]; +export type ReveredFetchPipeline = [FetchHandler, ...FetchMiddleware[]]; diff --git a/src/fetch-middleware/with-auth-token-required.ts b/src/fetch-middleware/with-auth-token-required.ts new file mode 100644 index 00000000..29327b48 --- /dev/null +++ b/src/fetch-middleware/with-auth-token-required.ts @@ -0,0 +1,32 @@ +import { createFetchMiddlewareDebug } from "./middleware-debug"; +import { FetchMiddleware } from "./types"; + +const debug = createFetchMiddlewareDebug("withAuthTokenRequired"); + +export const withAuthTokenRequired: FetchMiddleware = (handler) => async (request) => { + debug("Middleware called"); + + try { + // If we read `request.json()` without cloning it will throw an error + // next time we run request.json() + const clone = request.clone(); + const json = await clone.json(); + const authToken = json.auth_token; + + if (!authToken) { + debug("Found missing authToken param"); + + return Response.json( + { + success: false, + message: "Missing auth token.", + }, + { status: 400 } + ); + } + } catch { + return Response.json({ success: false, message: "Invalid request body" }, { status: 400 }); + } + + return handler(request); +}; diff --git a/src/fetch-middleware/with-method.ts b/src/fetch-middleware/with-method.ts new file mode 100644 index 00000000..73becfe2 --- /dev/null +++ b/src/fetch-middleware/with-method.ts @@ -0,0 +1,25 @@ +import { FetchMiddleware } from "./types"; + +export const HTTPMethod = { + GET: "GET", + POST: "POST", + PUT: "PUT", + PATH: "PATCH", + HEAD: "HEAD", + OPTIONS: "OPTIONS", + DELETE: "DELETE", +} as const; +export type HTTPMethod = typeof HTTPMethod[keyof typeof HTTPMethod]; + +export const withMethod = + (...methods: HTTPMethod[]): FetchMiddleware => + (handler) => + async (request) => { + if (!methods.includes(request.method as HTTPMethod)) { + return new Response("Method not allowed", { status: 405 }); + } + + const response = await handler(request); + + return response; + }; diff --git a/src/fetch-middleware/with-registered-saleor-domain-header.ts b/src/fetch-middleware/with-registered-saleor-domain-header.ts new file mode 100644 index 00000000..6e3edb12 --- /dev/null +++ b/src/fetch-middleware/with-registered-saleor-domain-header.ts @@ -0,0 +1,51 @@ +import { getSaleorHeadersFetchAPI } from "../headers"; +import { createFetchMiddlewareDebug } from "./middleware-debug"; +import { FetchMiddleware } from "./types"; +import { getSaleorAppFromRequest } from "./with-saleor-app"; + +const debug = createFetchMiddlewareDebug("withRegisteredSaleorDomainHeader"); + +export const withRegisteredSaleorDomainHeader: FetchMiddleware = (handler) => async (request) => { + const { saleorApiUrl } = getSaleorHeadersFetchAPI(request.headers); + + if (!saleorApiUrl) { + return Response.json( + { success: false, message: "saleorApiUrl header missing" }, + { status: 400 } + ); + } + + debug("Middleware called with saleorApiUrl: \"%s\"", saleorApiUrl); + + const saleorApp = getSaleorAppFromRequest(request); + + if (!saleorApp) { + console.error( + "SaleorApp not found in request context. Ensure your API handler is wrapped with withSaleorApp middleware" + ); + + return Response.json( + { + success: false, + message: "SaleorApp is misconfigured", + }, + { status: 500 } + ); + } + + const authData = await saleorApp?.apl.get(saleorApiUrl); + + if (!authData) { + debug("Auth was not found in APL, will respond with Forbidden status"); + + return Response.json( + { + success: false, + message: `Saleor: ${saleorApiUrl} not registered.`, + }, + { status: 403 } + ); + } + + return handler(request); +}; diff --git a/src/fetch-middleware/with-saleor-app.ts b/src/fetch-middleware/with-saleor-app.ts new file mode 100644 index 00000000..b95a754f --- /dev/null +++ b/src/fetch-middleware/with-saleor-app.ts @@ -0,0 +1,20 @@ +import { SaleorApp } from "../saleor-app"; +import { createFetchMiddlewareDebug } from "./middleware-debug"; +import { FetchMiddleware, SaleorRequest } from "./types"; + +const debug = createFetchMiddlewareDebug("withSaleorApp"); + +export const withSaleorApp = + (saleorApp: SaleorApp): FetchMiddleware => + (handler) => + async (request: SaleorRequest) => { + debug("Middleware called"); + + request.context ??= {}; + request.context.saleorApp = saleorApp; + + return handler(request); + }; + +export const getSaleorAppFromRequest = (request: SaleorRequest): SaleorApp | undefined => + request.context?.saleorApp; diff --git a/src/fetch-middleware/with-saleor-domain-present.ts b/src/fetch-middleware/with-saleor-domain-present.ts new file mode 100644 index 00000000..9955aa38 --- /dev/null +++ b/src/fetch-middleware/with-saleor-domain-present.ts @@ -0,0 +1,25 @@ +import { getSaleorHeadersFetchAPI } from "../headers"; +import { createFetchMiddlewareDebug } from "./middleware-debug"; +import { FetchMiddleware } from "./types"; + +const debug = createFetchMiddlewareDebug("withSaleorDomainPresent"); + +export const withSaleorDomainPresent: FetchMiddleware = (handler) => async (request) => { + const { domain } = getSaleorHeadersFetchAPI(request.headers); + + debug("Middleware called with domain in header: %s", domain); + + if (!domain) { + debug("Domain not found in header, will respond with Bad Request"); + + return Response.json( + { + success: false, + message: "Missing Saleor domain header.", + }, + { status: 400 } + ); + } + + return handler(request); +}; diff --git a/src/handlers/next-edge/create-app-register-handler.ts b/src/handlers/next-edge/create-app-register-handler.ts new file mode 100644 index 00000000..65d130eb --- /dev/null +++ b/src/handlers/next-edge/create-app-register-handler.ts @@ -0,0 +1,301 @@ +import { AuthData } from "../../APL"; +import { SALEOR_API_URL_HEADER, SALEOR_DOMAIN_HEADER } from "../../const"; +import { createDebug } from "../../debug"; +import { toNextEdgeHandler } from "../../fetch-middleware/to-next-edge-handler"; +import { FetchHandler } from "../../fetch-middleware/types"; +import { withAuthTokenRequired } from "../../fetch-middleware/with-auth-token-required"; +import { withMethod } from "../../fetch-middleware/with-method"; +import { withSaleorDomainPresent } from "../../fetch-middleware/with-saleor-domain-present"; +import { fetchRemoteJwks } from "../../fetch-remote-jwks"; +import { getAppId } from "../../get-app-id"; +import { HasAPL } from "../../saleor-app"; +import { validateAllowSaleorUrls } from "../next/validate-allow-saleor-urls"; + +const debug = createDebug("createAppRegisterHandler"); + +type HookCallbackErrorParams = { + status?: number; + message?: string; +}; + +class RegisterCallbackError extends Error { + public status = 500; + + constructor(errorParams: HookCallbackErrorParams) { + super(errorParams.message); + + if (errorParams.status) { + this.status = errorParams.status; + } + } +} + +const createCallbackError = (params: HookCallbackErrorParams) => { + throw new RegisterCallbackError(params); +}; + +export type RegisterHandlerResponseBody = { + success: boolean; + error?: { + code?: string; + message?: string; + }; +}; + +export const createRegisterHandlerResponseBody = ( + success: boolean, + error?: RegisterHandlerResponseBody["error"] +): RegisterHandlerResponseBody => ({ + success, + error, +}); + +const handleHookError = (e: RegisterCallbackError | unknown) => { + if (e instanceof RegisterCallbackError) { + return Response.json( + createRegisterHandlerResponseBody(false, { + code: "REGISTER_HANDLER_HOOK_ERROR", + message: e.message, + }), + { status: e.status } + ); + } + return new Response("Error during app installation", { status: 500 }); +}; + +export type CreateAppRegisterHandlerOptions = HasAPL & { + /** + * Protect app from being registered in Saleor other than specific. + * By default, allow everything. + * + * Provide array of either a full Saleor API URL (eg. my-shop.saleor.cloud/graphql/) + * or a function that receives a full Saleor API URL ad returns true/false. + */ + allowedSaleorUrls?: Array boolean)>; + /** + * Run right after Saleor calls this endpoint + */ + onRequestStart?( + request: Request, + context: { + authToken?: string; + saleorDomain?: string; + saleorApiUrl?: string; + respondWithError: typeof createCallbackError; + } + ): Promise; + /** + * Run after all security checks + */ + onRequestVerified?( + request: Request, + context: { + authData: AuthData; + respondWithError: typeof createCallbackError; + } + ): Promise; + /** + * Run after APL successfully AuthData, assuming that APL.set will reject a Promise in case of error + */ + onAuthAplSaved?( + request: Request, + context: { + authData: AuthData; + respondWithError: typeof createCallbackError; + } + ): Promise; + /** + * Run after APL fails to set AuthData + */ + onAplSetFailed?( + request: Request, + context: { + authData: AuthData; + error: unknown; + respondWithError: typeof createCallbackError; + } + ): Promise; +}; + +/** + * Creates API handler for Next.js. Creates handler called by Saleor that registers app. + * Hides implementation details if possible + * In the future this will be extracted to separate sdk/next package + */ +export const createAppRegisterHandler = ({ + apl, + allowedSaleorUrls, + onAplSetFailed, + onAuthAplSaved, + onRequestVerified, + onRequestStart, +}: CreateAppRegisterHandlerOptions) => { + const baseHandler: FetchHandler = async (inputRequest) => { + debug("Request received"); + + const request = inputRequest.clone(); + const json = await request.json(); + const authToken = json.auth_token; + const saleorDomain = request.headers.get(SALEOR_DOMAIN_HEADER) as string; + const saleorApiUrl = request.headers.get(SALEOR_API_URL_HEADER) as string; + + if (onRequestStart) { + debug("Calling \"onRequestStart\" hook"); + + try { + await onRequestStart(request, { + authToken, + saleorApiUrl, + saleorDomain, + respondWithError: createCallbackError, + }); + } catch (e: RegisterCallbackError | unknown) { + debug("\"onRequestStart\" hook thrown error: %o", e); + + return handleHookError(e); + } + } + + if (!saleorApiUrl) { + debug("saleorApiUrl doesnt exist in headers"); + } + + if (!validateAllowSaleorUrls(saleorApiUrl, allowedSaleorUrls)) { + debug( + "Validation of URL %s against allowSaleorUrls param resolves to false, throwing", + saleorApiUrl + ); + + return Response.json( + createRegisterHandlerResponseBody(false, { + code: "SALEOR_URL_PROHIBITED", + message: "This app expects to be installed only in allowed Saleor instances", + }), + { status: 403 } + ); + } + + const { configured: aplConfigured } = await apl.isConfigured(); + + if (!aplConfigured) { + debug("The APL has not been configured"); + + return Response.json( + createRegisterHandlerResponseBody(false, { + code: "APL_NOT_CONFIGURED", + message: "APL_NOT_CONFIGURED. App is configured properly. Check APL docs for help.", + }), + { + status: 503, + } + ); + } + + // Try to get App ID from the API, to confirm that communication can be established + const appId = await getAppId({ saleorApiUrl, token: authToken }); + if (!appId) { + return Response.json( + createRegisterHandlerResponseBody(false, { + code: "UNKNOWN_APP_ID", + message: `The auth data given during registration request could not be used to fetch app ID. + This usually means that App could not connect to Saleor during installation. Saleor URL that App tried to connect: ${saleorApiUrl}`, + }), + { + status: 401, + } + ); + } + + // Fetch the JWKS which will be used during webhook validation + const jwks = await fetchRemoteJwks(saleorApiUrl); + if (!jwks) { + return Response.json( + createRegisterHandlerResponseBody(false, { + code: "JWKS_NOT_AVAILABLE", + message: "Can't fetch the remote JWKS.", + }), + { + status: 401, + } + ); + } + + const authData = { + domain: saleorDomain, + token: authToken, + saleorApiUrl, + appId, + jwks, + }; + + if (onRequestVerified) { + debug("Calling \"onRequestVerified\" hook"); + + try { + await onRequestVerified(request, { + authData, + respondWithError: createCallbackError, + }); + } catch (e: RegisterCallbackError | unknown) { + debug("\"onRequestVerified\" hook thrown error: %o", e); + + return handleHookError(e); + } + } + + try { + await apl.set(authData); + + if (onAuthAplSaved) { + debug("Calling \"onAuthAplSaved\" hook"); + + try { + await onAuthAplSaved(request, { + authData, + respondWithError: createCallbackError, + }); + } catch (e: RegisterCallbackError | unknown) { + debug("\"onAuthAplSaved\" hook thrown error: %o", e); + + return handleHookError(e); + } + } + } catch (aplError: unknown) { + debug("There was an error during saving the auth data"); + + if (onAplSetFailed) { + debug("Calling \"onAuthAplFailed\" hook"); + + try { + await onAplSetFailed(request, { + authData, + error: aplError, + respondWithError: createCallbackError, + }); + } catch (hookError: RegisterCallbackError | unknown) { + debug("\"onAuthAplFailed\" hook thrown error: %o", hookError); + + return handleHookError(hookError); + } + } + + return Response.json( + createRegisterHandlerResponseBody(false, { + message: "Registration failed: could not save the auth data.", + }), + { status: 500 } + ); + } + + debug("Register complete"); + + return Response.json(createRegisterHandlerResponseBody(true)); + }; + + return toNextEdgeHandler([ + withMethod("POST"), + withSaleorDomainPresent, + withAuthTokenRequired, + baseHandler, + ]); +}; diff --git a/src/handlers/next-edge/index.ts b/src/handlers/next-edge/index.ts index 037eb059..9edd583e 100644 --- a/src/handlers/next-edge/index.ts +++ b/src/handlers/next-edge/index.ts @@ -1 +1,2 @@ +export * from "./create-app-register-handler"; export * from "./create-manifest-handler"; diff --git a/tsup.config.ts b/tsup.config.ts index 5d26e0be..7b73e8df 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -15,6 +15,7 @@ export default defineConfig({ "src/app-bridge/next/index.ts", "src/handlers/next/index.ts", "src/handlers/next-edge/index.ts", + "src/fetch-middleware/index.ts", "src/middleware/index.ts", "src/settings-manager/index.ts", ], From 4ddd53c7eac993e5e072f4f7bec20723bd84f845 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Mon, 23 Dec 2024 15:25:14 +0100 Subject: [PATCH 09/58] Add `Allow` header for HTTP 405 --- src/fetch-middleware/with-method.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/fetch-middleware/with-method.ts b/src/fetch-middleware/with-method.ts index 73becfe2..0f9effaa 100644 --- a/src/fetch-middleware/with-method.ts +++ b/src/fetch-middleware/with-method.ts @@ -16,7 +16,10 @@ export const withMethod = (handler) => async (request) => { if (!methods.includes(request.method as HTTPMethod)) { - return new Response("Method not allowed", { status: 405 }); + return new Response("Method not allowed", { + status: 405, + headers: { Allow: methods.join(", ") }, + }); } const response = await handler(request); From 09da9c2ccfe8d40d5b162468508851ef56ead55c Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Mon, 23 Dec 2024 16:31:03 +0100 Subject: [PATCH 10/58] Rename next-edge -> fetch-api --- .../{next-edge => fetch-api}/create-app-register-handler.ts | 2 +- .../{next-edge => fetch-api}/create-manifest-handler.ts | 0 src/handlers/{next-edge => fetch-api}/index.ts | 0 .../{next => shared}/validate-allow-saleor-urls.test.ts | 0 src/handlers/{next => shared}/validate-allow-saleor-urls.ts | 0 5 files changed, 1 insertion(+), 1 deletion(-) rename src/handlers/{next-edge => fetch-api}/create-app-register-handler.ts (99%) rename src/handlers/{next-edge => fetch-api}/create-manifest-handler.ts (100%) rename src/handlers/{next-edge => fetch-api}/index.ts (100%) rename src/handlers/{next => shared}/validate-allow-saleor-urls.test.ts (100%) rename src/handlers/{next => shared}/validate-allow-saleor-urls.ts (100%) diff --git a/src/handlers/next-edge/create-app-register-handler.ts b/src/handlers/fetch-api/create-app-register-handler.ts similarity index 99% rename from src/handlers/next-edge/create-app-register-handler.ts rename to src/handlers/fetch-api/create-app-register-handler.ts index 65d130eb..282bf808 100644 --- a/src/handlers/next-edge/create-app-register-handler.ts +++ b/src/handlers/fetch-api/create-app-register-handler.ts @@ -9,7 +9,7 @@ import { withSaleorDomainPresent } from "../../fetch-middleware/with-saleor-doma import { fetchRemoteJwks } from "../../fetch-remote-jwks"; import { getAppId } from "../../get-app-id"; import { HasAPL } from "../../saleor-app"; -import { validateAllowSaleorUrls } from "../next/validate-allow-saleor-urls"; +import { validateAllowSaleorUrls } from "../shared/validate-allow-saleor-urls"; const debug = createDebug("createAppRegisterHandler"); diff --git a/src/handlers/next-edge/create-manifest-handler.ts b/src/handlers/fetch-api/create-manifest-handler.ts similarity index 100% rename from src/handlers/next-edge/create-manifest-handler.ts rename to src/handlers/fetch-api/create-manifest-handler.ts diff --git a/src/handlers/next-edge/index.ts b/src/handlers/fetch-api/index.ts similarity index 100% rename from src/handlers/next-edge/index.ts rename to src/handlers/fetch-api/index.ts diff --git a/src/handlers/next/validate-allow-saleor-urls.test.ts b/src/handlers/shared/validate-allow-saleor-urls.test.ts similarity index 100% rename from src/handlers/next/validate-allow-saleor-urls.test.ts rename to src/handlers/shared/validate-allow-saleor-urls.test.ts diff --git a/src/handlers/next/validate-allow-saleor-urls.ts b/src/handlers/shared/validate-allow-saleor-urls.ts similarity index 100% rename from src/handlers/next/validate-allow-saleor-urls.ts rename to src/handlers/shared/validate-allow-saleor-urls.ts From d1dc948f6df5789b49d185c677d8f0b030517642 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Mon, 23 Dec 2024 16:32:40 +0100 Subject: [PATCH 11/58] Update changeset --- .changeset/fluffy-cheetahs-sleep.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/fluffy-cheetahs-sleep.md b/.changeset/fluffy-cheetahs-sleep.md index e7de93f0..6b11227c 100644 --- a/.changeset/fluffy-cheetahs-sleep.md +++ b/.changeset/fluffy-cheetahs-sleep.md @@ -2,4 +2,4 @@ "@saleor/app-sdk": minor --- -Experimental: Added `handlers/next-edge` which adds support for Next.js Edge Runtime +Added `handlers/fetch-api` which adds support for frameworks that use [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) From 9d34b5f8594729ad0587d268f83d212e9e89f242 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Mon, 23 Dec 2024 16:43:45 +0100 Subject: [PATCH 12/58] Add shared interface, remove usage of "NextEdge" --- src/fetch-middleware/index.ts | 2 +- ...-edge-handler.ts => to-request-handler.ts} | 2 +- .../fetch-api/create-app-register-handler.ts | 75 +++---------------- .../next/create-app-register-handler.ts | 62 ++------------- .../create-app-register-handler-types.ts | 63 ++++++++++++++++ .../shared/validate-allow-saleor-urls.ts | 2 +- 6 files changed, 82 insertions(+), 124 deletions(-) rename src/fetch-middleware/{to-next-edge-handler.ts => to-request-handler.ts} (87%) create mode 100644 src/handlers/shared/create-app-register-handler-types.ts diff --git a/src/fetch-middleware/index.ts b/src/fetch-middleware/index.ts index b0e4eef1..25af3044 100644 --- a/src/fetch-middleware/index.ts +++ b/src/fetch-middleware/index.ts @@ -1,4 +1,4 @@ -export * from "./to-next-edge-handler"; +export * from "./to-request-handler"; export * from "./with-auth-token-required"; export * from "./with-method"; export * from "./with-registered-saleor-domain-header"; diff --git a/src/fetch-middleware/to-next-edge-handler.ts b/src/fetch-middleware/to-request-handler.ts similarity index 87% rename from src/fetch-middleware/to-next-edge-handler.ts rename to src/fetch-middleware/to-request-handler.ts index df35a3d6..0ca5f375 100644 --- a/src/fetch-middleware/to-next-edge-handler.ts +++ b/src/fetch-middleware/to-request-handler.ts @@ -13,7 +13,7 @@ const preparePipeline = (pipeline: FetchPipeline): FetchHandler => { return compose(...middleware)(action); }; -export const toNextEdgeHandler = (flow: FetchHandler | FetchPipeline): FetchHandler => { +export const toRequestHandler = (flow: FetchHandler | FetchPipeline): FetchHandler => { const handler = isPipeline(flow) ? preparePipeline(flow) : flow; return async (request: Request) => handler(request); diff --git a/src/handlers/fetch-api/create-app-register-handler.ts b/src/handlers/fetch-api/create-app-register-handler.ts index 282bf808..f80177c7 100644 --- a/src/handlers/fetch-api/create-app-register-handler.ts +++ b/src/handlers/fetch-api/create-app-register-handler.ts @@ -1,23 +1,21 @@ -import { AuthData } from "../../APL"; import { SALEOR_API_URL_HEADER, SALEOR_DOMAIN_HEADER } from "../../const"; import { createDebug } from "../../debug"; -import { toNextEdgeHandler } from "../../fetch-middleware/to-next-edge-handler"; +import { toRequestHandler } from "../../fetch-middleware/to-request-handler"; import { FetchHandler } from "../../fetch-middleware/types"; import { withAuthTokenRequired } from "../../fetch-middleware/with-auth-token-required"; import { withMethod } from "../../fetch-middleware/with-method"; import { withSaleorDomainPresent } from "../../fetch-middleware/with-saleor-domain-present"; import { fetchRemoteJwks } from "../../fetch-remote-jwks"; import { getAppId } from "../../get-app-id"; -import { HasAPL } from "../../saleor-app"; +import { + CallbackErrorHandler, + GenericCreateAppRegisterHandlerOptions, + HookCallbackErrorParams, +} from "../shared/create-app-register-handler-types"; import { validateAllowSaleorUrls } from "../shared/validate-allow-saleor-urls"; const debug = createDebug("createAppRegisterHandler"); -type HookCallbackErrorParams = { - status?: number; - message?: string; -}; - class RegisterCallbackError extends Error { public status = 500; @@ -30,7 +28,7 @@ class RegisterCallbackError extends Error { } } -const createCallbackError = (params: HookCallbackErrorParams) => { +const createCallbackError: CallbackErrorHandler = (params: HookCallbackErrorParams) => { throw new RegisterCallbackError(params); }; @@ -63,59 +61,8 @@ const handleHookError = (e: RegisterCallbackError | unknown) => { return new Response("Error during app installation", { status: 500 }); }; -export type CreateAppRegisterHandlerOptions = HasAPL & { - /** - * Protect app from being registered in Saleor other than specific. - * By default, allow everything. - * - * Provide array of either a full Saleor API URL (eg. my-shop.saleor.cloud/graphql/) - * or a function that receives a full Saleor API URL ad returns true/false. - */ - allowedSaleorUrls?: Array boolean)>; - /** - * Run right after Saleor calls this endpoint - */ - onRequestStart?( - request: Request, - context: { - authToken?: string; - saleorDomain?: string; - saleorApiUrl?: string; - respondWithError: typeof createCallbackError; - } - ): Promise; - /** - * Run after all security checks - */ - onRequestVerified?( - request: Request, - context: { - authData: AuthData; - respondWithError: typeof createCallbackError; - } - ): Promise; - /** - * Run after APL successfully AuthData, assuming that APL.set will reject a Promise in case of error - */ - onAuthAplSaved?( - request: Request, - context: { - authData: AuthData; - respondWithError: typeof createCallbackError; - } - ): Promise; - /** - * Run after APL fails to set AuthData - */ - onAplSetFailed?( - request: Request, - context: { - authData: AuthData; - error: unknown; - respondWithError: typeof createCallbackError; - } - ): Promise; -}; +// Request type is from Web API +export type CreateAppRegisterHandlerOptions = GenericCreateAppRegisterHandlerOptions; /** * Creates API handler for Next.js. Creates handler called by Saleor that registers app. @@ -157,7 +104,7 @@ export const createAppRegisterHandler = ({ } if (!saleorApiUrl) { - debug("saleorApiUrl doesnt exist in headers"); + debug("saleorApiUrl doesn't exist in headers"); } if (!validateAllowSaleorUrls(saleorApiUrl, allowedSaleorUrls)) { @@ -292,7 +239,7 @@ export const createAppRegisterHandler = ({ return Response.json(createRegisterHandlerResponseBody(true)); }; - return toNextEdgeHandler([ + return toRequestHandler([ withMethod("POST"), withSaleorDomainPresent, withAuthTokenRequired, diff --git a/src/handlers/next/create-app-register-handler.ts b/src/handlers/next/create-app-register-handler.ts index 1e0da6de..edc178ed 100644 --- a/src/handlers/next/create-app-register-handler.ts +++ b/src/handlers/next/create-app-register-handler.ts @@ -3,14 +3,13 @@ import { toNextHandler } from "retes/adapter"; import { withMethod } from "retes/middleware"; import { Response } from "retes/response"; -import { AuthData } from "../../APL"; import { SALEOR_API_URL_HEADER, SALEOR_DOMAIN_HEADER } from "../../const"; import { createDebug } from "../../debug"; import { fetchRemoteJwks } from "../../fetch-remote-jwks"; import { getAppId } from "../../get-app-id"; import { withAuthTokenRequired, withSaleorDomainPresent } from "../../middleware"; -import { HasAPL } from "../../saleor-app"; -import { validateAllowSaleorUrls } from "./validate-allow-saleor-urls"; +import { GenericCreateAppRegisterHandlerOptions } from "../shared/create-app-register-handler-types"; +import { validateAllowSaleorUrls } from "../shared/validate-allow-saleor-urls"; const debug = createDebug("createAppRegisterHandler"); @@ -63,59 +62,8 @@ const handleHookError = (e: RegisterCallbackError | unknown) => { return Response.InternalServerError("Error during app installation"); }; -export type CreateAppRegisterHandlerOptions = HasAPL & { - /** - * Protect app from being registered in Saleor other than specific. - * By default, allow everything. - * - * Provide array of either a full Saleor API URL (eg. my-shop.saleor.cloud/graphql/) - * or a function that receives a full Saleor API URL ad returns true/false. - */ - allowedSaleorUrls?: Array boolean)>; - /** - * Run right after Saleor calls this endpoint - */ - onRequestStart?( - request: Request, - context: { - authToken?: string; - saleorDomain?: string; - saleorApiUrl?: string; - respondWithError: typeof createCallbackError; - } - ): Promise; - /** - * Run after all security checks - */ - onRequestVerified?( - request: Request, - context: { - authData: AuthData; - respondWithError: typeof createCallbackError; - } - ): Promise; - /** - * Run after APL successfully AuthData, assuming that APL.set will reject a Promise in case of error - */ - onAuthAplSaved?( - request: Request, - context: { - authData: AuthData; - respondWithError: typeof createCallbackError; - } - ): Promise; - /** - * Run after APL fails to set AuthData - */ - onAplSetFailed?( - request: Request, - context: { - authData: AuthData; - error: unknown; - respondWithError: typeof createCallbackError; - } - ): Promise; -}; +// Request type is from retest (Next.js interface) +export type CreateAppRegisterHandlerOptions = GenericCreateAppRegisterHandlerOptions; /** * Creates API handler for Next.js. Creates handler called by Saleor that registers app. @@ -155,7 +103,7 @@ export const createAppRegisterHandler = ({ } if (!saleorApiUrl) { - debug("saleorApiUrl doesnt exist in headers"); + debug("saleorApiUrl doesn't exist in headers"); } if (!validateAllowSaleorUrls(saleorApiUrl, allowedSaleorUrls)) { diff --git a/src/handlers/shared/create-app-register-handler-types.ts b/src/handlers/shared/create-app-register-handler-types.ts new file mode 100644 index 00000000..a35d369d --- /dev/null +++ b/src/handlers/shared/create-app-register-handler-types.ts @@ -0,0 +1,63 @@ +import { AuthData } from "../../APL"; +import { HasAPL } from "../../saleor-app"; + +export type HookCallbackErrorParams = { + status?: number; + message?: string; +}; + +export type CallbackErrorHandler = (params: HookCallbackErrorParams) => never; + +export type GenericCreateAppRegisterHandlerOptions = HasAPL & { + /** + * Protect app from being registered in Saleor other than specific. + * By default, allow everything. + * + * Provide array of either a full Saleor API URL (eg. my-shop.saleor.cloud/graphql/) + * or a function that receives a full Saleor API URL ad returns true/false. + */ + allowedSaleorUrls?: Array boolean)>; + /** + * Run right after Saleor calls this endpoint + */ + onRequestStart?( + request: RequestType, + context: { + authToken?: string; + saleorDomain?: string; + saleorApiUrl?: string; + respondWithError: CallbackErrorHandler; + } + ): Promise; + /** + * Run after all security checks + */ + onRequestVerified?( + request: RequestType, + context: { + authData: AuthData; + respondWithError: CallbackErrorHandler; + } + ): Promise; + /** + * Run after APL successfully AuthData, assuming that APL.set will reject a Promise in case of error + */ + onAuthAplSaved?( + request: RequestType, + context: { + authData: AuthData; + respondWithError: CallbackErrorHandler; + } + ): Promise; + /** + * Run after APL fails to set AuthData + */ + onAplSetFailed?( + request: RequestType, + context: { + authData: AuthData; + error: unknown; + respondWithError: CallbackErrorHandler; + } + ): Promise; +}; diff --git a/src/handlers/shared/validate-allow-saleor-urls.ts b/src/handlers/shared/validate-allow-saleor-urls.ts index 9b7c39c5..03875027 100644 --- a/src/handlers/shared/validate-allow-saleor-urls.ts +++ b/src/handlers/shared/validate-allow-saleor-urls.ts @@ -1,4 +1,4 @@ -import { CreateAppRegisterHandlerOptions } from "./create-app-register-handler"; +import { CreateAppRegisterHandlerOptions } from "../next/create-app-register-handler"; export const validateAllowSaleorUrls = ( saleorApiUrl: string, From a4f75be0a52e96ed358a9a27956e8befe74056bb Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Mon, 23 Dec 2024 17:16:23 +0100 Subject: [PATCH 13/58] Add protected route handler --- .../fetch-api/create-app-register-handler.ts | 2 +- .../fetch-api/create-protected-handler.ts | 35 ++++ .../fetch-api/process-protected-handler.ts | 163 ++++++++++++++++++ src/handlers/next/create-protected-handler.ts | 20 +-- src/handlers/next/index.ts | 2 +- .../next/process-protected-handler.ts | 2 +- .../protected-handler-context.ts | 0 src/handlers/shared/protected-handler.ts | 12 ++ 8 files changed, 216 insertions(+), 20 deletions(-) create mode 100644 src/handlers/fetch-api/create-protected-handler.ts create mode 100644 src/handlers/fetch-api/process-protected-handler.ts rename src/handlers/{next => shared}/protected-handler-context.ts (100%) create mode 100644 src/handlers/shared/protected-handler.ts diff --git a/src/handlers/fetch-api/create-app-register-handler.ts b/src/handlers/fetch-api/create-app-register-handler.ts index f80177c7..2d96c062 100644 --- a/src/handlers/fetch-api/create-app-register-handler.ts +++ b/src/handlers/fetch-api/create-app-register-handler.ts @@ -14,7 +14,7 @@ import { } from "../shared/create-app-register-handler-types"; import { validateAllowSaleorUrls } from "../shared/validate-allow-saleor-urls"; -const debug = createDebug("createAppRegisterHandler"); +const debug = createDebug("WebApi:createAppRegisterHandler"); class RegisterCallbackError extends Error { public status = 500; diff --git a/src/handlers/fetch-api/create-protected-handler.ts b/src/handlers/fetch-api/create-protected-handler.ts new file mode 100644 index 00000000..f5b88f38 --- /dev/null +++ b/src/handlers/fetch-api/create-protected-handler.ts @@ -0,0 +1,35 @@ +import { APL } from "../../APL"; +import { createDebug } from "../../debug"; +import { Permission } from "../../types"; +import { ProtectedHandlerErrorCodeMap } from "../shared/protected-handler"; +import { processSaleorProtectedHandler, ProtectedHandlerError } from "./process-protected-handler"; + +const debug = createDebug("WebAPI:ProtectedHandler"); + +type WebApiHandlerFn = (request: Request) => Response | Promise; + +export const createProtectedHandler = + (handlerFn: WebApiHandlerFn, apl: APL, requiredPermissions?: Permission[]): WebApiHandlerFn => + (request) => { + debug("Protected handler called"); + return ( + processSaleorProtectedHandler({ request, apl, requiredPermissions }) + // TODO: Pass context + .then(async () => { + debug("Incoming request validated. Call handlerFn"); + return handlerFn(request); + }) + .catch((e) => { + debug("Unexpected error during processing the request"); + + if (e instanceof ProtectedHandlerError) { + debug(`Validation error: ${e.message}`); + return new Response("Invalid request", { + status: ProtectedHandlerErrorCodeMap[e.errorType] || 400, + }); + } + debug("Unexpected error: %O", e); + return new Response("Unexpected error while handling request", { status: 500 }); + }) + ); + }; diff --git a/src/handlers/fetch-api/process-protected-handler.ts b/src/handlers/fetch-api/process-protected-handler.ts new file mode 100644 index 00000000..447298a2 --- /dev/null +++ b/src/handlers/fetch-api/process-protected-handler.ts @@ -0,0 +1,163 @@ +import { SpanKind, SpanStatusCode } from "@opentelemetry/api"; + +import { APL } from "../../APL"; +import { createDebug } from "../../debug"; +import { getBaseUrlFetchAPI, getSaleorHeadersFetchAPI } from "../../headers"; +import { getOtelTracer } from "../../open-telemetry"; +import { Permission } from "../../types"; +import { extractUserFromJwt } from "../../util/extract-user-from-jwt"; +import { verifyJWT } from "../../verify-jwt"; +import { ProtectedHandlerContext } from "../shared/protected-handler-context"; + +const debug = createDebug("processProtectedHandler"); + +export type SaleorProtectedHandlerError = + | "OTHER" + | "MISSING_HOST_HEADER" + | "MISSING_DOMAIN_HEADER" + | "MISSING_API_URL_HEADER" + | "MISSING_AUTHORIZATION_BEARER_HEADER" + | "NOT_REGISTERED" + | "JWT_VERIFICATION_FAILED" + | "NO_APP_ID"; + +export class ProtectedHandlerError extends Error { + errorType: SaleorProtectedHandlerError = "OTHER"; + + constructor(message: string, errorType: SaleorProtectedHandlerError) { + super(message); + if (errorType) { + this.errorType = errorType; + } + Object.setPrototypeOf(this, ProtectedHandlerError.prototype); + } +} + +interface ProcessSaleorProtectedHandlerArgs { + request: Pick; + apl: APL; + requiredPermissions?: Permission[]; +} + +type ProcessAsyncSaleorProtectedHandler = ( + props: ProcessSaleorProtectedHandlerArgs +) => Promise; + +/** + * Perform security checks on given request and return ProtectedHandlerContext object. + * In case of validation issues, instance of the ProtectedHandlerError will be thrown. + * + * Can pass entire next request or Headers with saleorApiUrl and token + */ +export const processSaleorProtectedHandler: ProcessAsyncSaleorProtectedHandler = async ({ + request, + apl, + requiredPermissions, +}: ProcessSaleorProtectedHandlerArgs): Promise => { + const tracer = getOtelTracer(); + + return tracer.startActiveSpan( + "processSaleorProtectedHandler", + { + kind: SpanKind.INTERNAL, + attributes: { + requiredPermissions, + }, + }, + async (span) => { + debug("Request processing started"); + + const { saleorApiUrl, authorizationBearer: token } = getSaleorHeadersFetchAPI( + request.headers + ); + + const baseUrl = getBaseUrlFetchAPI(request.headers); + + span.setAttribute("saleorApiUrl", saleorApiUrl ?? ""); + + if (!baseUrl) { + span + .setStatus({ + code: SpanStatusCode.ERROR, + message: "Missing host header", + }) + .end(); + + debug("Missing host header"); + + throw new ProtectedHandlerError("Missing host header", "MISSING_HOST_HEADER"); + } + + if (!saleorApiUrl) { + span + .setStatus({ + code: SpanStatusCode.ERROR, + message: "Missing saleor-api-url header", + }) + .end(); + + debug("Missing saleor-api-url header"); + + throw new ProtectedHandlerError("Missing saleor-api-url header", "MISSING_API_URL_HEADER"); + } + + if (!token) { + span + .setStatus({ + code: SpanStatusCode.ERROR, + message: "Missing authorization-bearer header", + }) + .end(); + + debug("Missing authorization-bearer header"); + + throw new ProtectedHandlerError( + "Missing authorization-bearer header", + "MISSING_AUTHORIZATION_BEARER_HEADER" + ); + } + + // Check if API URL has been registered in the APL + const authData = await apl.get(saleorApiUrl); + + if (!authData) { + span + .setStatus({ + code: SpanStatusCode.ERROR, + message: "APL didn't found auth data for API URL", + }) + .end(); + + debug("APL didn't found auth data for API URL %s", saleorApiUrl); + + throw new ProtectedHandlerError( + `Can't find auth data for saleorApiUrl ${saleorApiUrl}. Please register the application`, + "NOT_REGISTERED" + ); + } + + try { + await verifyJWT({ appId: authData.appId, token, saleorApiUrl, requiredPermissions }); + } catch (e) { + span + .setStatus({ + code: SpanStatusCode.ERROR, + message: "JWT verification failed", + }) + .end(); + + throw new ProtectedHandlerError("JWT verification failed: ", "JWT_VERIFICATION_FAILED"); + } + + const userJwtPayload = extractUserFromJwt(token); + + span.end(); + + return { + baseUrl, + authData, + user: userJwtPayload, + }; + } + ); +}; diff --git a/src/handlers/next/create-protected-handler.ts b/src/handlers/next/create-protected-handler.ts index 44027670..f8610569 100644 --- a/src/handlers/next/create-protected-handler.ts +++ b/src/handlers/next/create-protected-handler.ts @@ -3,26 +3,12 @@ import { NextApiHandler, NextApiRequest, NextApiResponse } from "next"; import { APL } from "../../APL"; import { createDebug } from "../../debug"; import { Permission } from "../../types"; -import { - processSaleorProtectedHandler, - ProtectedHandlerError, - SaleorProtectedHandlerError, -} from "./process-protected-handler"; -import { ProtectedHandlerContext } from "./protected-handler-context"; +import { ProtectedHandlerErrorCodeMap } from "../shared/protected-handler"; +import { ProtectedHandlerContext } from "../shared/protected-handler-context"; +import { processSaleorProtectedHandler, ProtectedHandlerError } from "./process-protected-handler"; const debug = createDebug("ProtectedHandler"); -export const ProtectedHandlerErrorCodeMap: Record = { - OTHER: 500, - MISSING_HOST_HEADER: 400, - MISSING_DOMAIN_HEADER: 400, - MISSING_API_URL_HEADER: 400, - NOT_REGISTERED: 401, - JWT_VERIFICATION_FAILED: 401, - NO_APP_ID: 401, - MISSING_AUTHORIZATION_BEARER_HEADER: 400, -}; - export type NextProtectedApiHandler = ( req: NextApiRequest, res: NextApiResponse, diff --git a/src/handlers/next/index.ts b/src/handlers/next/index.ts index 23ddd049..d4341e1a 100644 --- a/src/handlers/next/index.ts +++ b/src/handlers/next/index.ts @@ -1,8 +1,8 @@ +export * from "../shared/protected-handler-context"; export * from "./create-app-register-handler"; export * from "./create-manifest-handler"; export * from "./create-protected-handler"; export * from "./process-protected-handler"; -export * from "./protected-handler-context"; export * from "./saleor-webhooks/saleor-async-webhook"; export * from "./saleor-webhooks/saleor-sync-webhook"; export { NextWebhookApiHandler } from "./saleor-webhooks/saleor-webhook"; diff --git a/src/handlers/next/process-protected-handler.ts b/src/handlers/next/process-protected-handler.ts index f3f86e3c..020763be 100644 --- a/src/handlers/next/process-protected-handler.ts +++ b/src/handlers/next/process-protected-handler.ts @@ -8,7 +8,7 @@ import { getOtelTracer } from "../../open-telemetry"; import { Permission } from "../../types"; import { extractUserFromJwt } from "../../util/extract-user-from-jwt"; import { verifyJWT } from "../../verify-jwt"; -import { ProtectedHandlerContext } from "./protected-handler-context"; +import { ProtectedHandlerContext } from "../shared/protected-handler-context"; const debug = createDebug("processProtectedHandler"); diff --git a/src/handlers/next/protected-handler-context.ts b/src/handlers/shared/protected-handler-context.ts similarity index 100% rename from src/handlers/next/protected-handler-context.ts rename to src/handlers/shared/protected-handler-context.ts diff --git a/src/handlers/shared/protected-handler.ts b/src/handlers/shared/protected-handler.ts new file mode 100644 index 00000000..bcf64907 --- /dev/null +++ b/src/handlers/shared/protected-handler.ts @@ -0,0 +1,12 @@ +import { SaleorProtectedHandlerError } from "../next"; + +export const ProtectedHandlerErrorCodeMap: Record = { + OTHER: 500, + MISSING_HOST_HEADER: 400, + MISSING_DOMAIN_HEADER: 400, + MISSING_API_URL_HEADER: 400, + NOT_REGISTERED: 401, + JWT_VERIFICATION_FAILED: 401, + NO_APP_ID: 401, + MISSING_AUTHORIZATION_BEARER_HEADER: 400, +}; From 8f9a334c24f96de89bd4fdd8329c4d111dcbd8e2 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Tue, 24 Dec 2024 13:30:55 +0100 Subject: [PATCH 14/58] Add context to protected handler --- .../fetch-api/create-protected-handler.ts | 47 ++++++++++--------- src/handlers/next/index.ts | 1 + 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/handlers/fetch-api/create-protected-handler.ts b/src/handlers/fetch-api/create-protected-handler.ts index f5b88f38..e035cd0a 100644 --- a/src/handlers/fetch-api/create-protected-handler.ts +++ b/src/handlers/fetch-api/create-protected-handler.ts @@ -2,34 +2,39 @@ import { APL } from "../../APL"; import { createDebug } from "../../debug"; import { Permission } from "../../types"; import { ProtectedHandlerErrorCodeMap } from "../shared/protected-handler"; +import { ProtectedHandlerContext } from "../shared/protected-handler-context"; import { processSaleorProtectedHandler, ProtectedHandlerError } from "./process-protected-handler"; const debug = createDebug("WebAPI:ProtectedHandler"); -type WebApiHandlerFn = (request: Request) => Response | Promise; +export type WebApiProtectedHandler = ( + request: Request, + ctx: ProtectedHandlerContext +) => Response | Promise; export const createProtectedHandler = - (handlerFn: WebApiHandlerFn, apl: APL, requiredPermissions?: Permission[]): WebApiHandlerFn => + ( + handlerFn: WebApiProtectedHandler, + apl: APL, + requiredPermissions?: Permission[] + ): WebApiProtectedHandler => (request) => { debug("Protected handler called"); - return ( - processSaleorProtectedHandler({ request, apl, requiredPermissions }) - // TODO: Pass context - .then(async () => { - debug("Incoming request validated. Call handlerFn"); - return handlerFn(request); - }) - .catch((e) => { - debug("Unexpected error during processing the request"); + return processSaleorProtectedHandler({ request, apl, requiredPermissions }) + .then(async (ctx) => { + debug("Incoming request validated. Call handlerFn"); + return handlerFn(request, ctx); + }) + .catch((e) => { + debug("Unexpected error during processing the request"); - if (e instanceof ProtectedHandlerError) { - debug(`Validation error: ${e.message}`); - return new Response("Invalid request", { - status: ProtectedHandlerErrorCodeMap[e.errorType] || 400, - }); - } - debug("Unexpected error: %O", e); - return new Response("Unexpected error while handling request", { status: 500 }); - }) - ); + if (e instanceof ProtectedHandlerError) { + debug(`Validation error: ${e.message}`); + return new Response("Invalid request", { + status: ProtectedHandlerErrorCodeMap[e.errorType] || 400, + }); + } + debug("Unexpected error: %O", e); + return new Response("Unexpected error while handling request", { status: 500 }); + }); }; diff --git a/src/handlers/next/index.ts b/src/handlers/next/index.ts index d4341e1a..cd407d00 100644 --- a/src/handlers/next/index.ts +++ b/src/handlers/next/index.ts @@ -1,3 +1,4 @@ +// Re-export to avoid breaking changes export * from "../shared/protected-handler-context"; export * from "./create-app-register-handler"; export * from "./create-manifest-handler"; From c4eb069d8d3a822f740dff4cc3ff96343443487b Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Thu, 2 Jan 2025 15:33:25 +0100 Subject: [PATCH 15/58] Fix broken build --- src/handlers/fetch-api/index.ts | 5 +++++ src/handlers/shared/index.ts | 1 + tsup.config.ts | 3 ++- 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 src/handlers/shared/index.ts diff --git a/src/handlers/fetch-api/index.ts b/src/handlers/fetch-api/index.ts index 9edd583e..42f05125 100644 --- a/src/handlers/fetch-api/index.ts +++ b/src/handlers/fetch-api/index.ts @@ -1,2 +1,7 @@ export * from "./create-app-register-handler"; export * from "./create-manifest-handler"; +export * from "./create-protected-handler"; +export * from "./process-protected-handler"; +// export * from "./saleor-webhooks/saleor-async-webhook"; +// export * from "./saleor-webhooks/saleor-sync-webhook"; +// export * from "./saleor-webhooks/sync-webhook-response-builder"; diff --git a/src/handlers/shared/index.ts b/src/handlers/shared/index.ts new file mode 100644 index 00000000..abb51a05 --- /dev/null +++ b/src/handlers/shared/index.ts @@ -0,0 +1 @@ +export * from "./protected-handler-context"; diff --git a/tsup.config.ts b/tsup.config.ts index 7b73e8df..f6e5aa38 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -14,7 +14,8 @@ export default defineConfig({ "src/app-bridge/index.ts", "src/app-bridge/next/index.ts", "src/handlers/next/index.ts", - "src/handlers/next-edge/index.ts", + "src/handlers/fetch-api/index.ts", + "src/handlers/shared/index.ts", "src/fetch-middleware/index.ts", "src/middleware/index.ts", "src/settings-manager/index.ts", From b0a237a1d2ffeb513acd4d0b6d83803becc227d1 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Thu, 2 Jan 2025 15:34:57 +0100 Subject: [PATCH 16/58] Fix exports in package.json --- package.json | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index a0df9f27..2afa2030 100644 --- a/package.json +++ b/package.json @@ -138,10 +138,15 @@ "import": "./handlers/next/index.mjs", "require": "./handlers/next/index.js" }, - "./handlers/next-edge": { - "types": "./handlers/next-edge/index.d.ts", - "import": "./handlers/next-edge/index.mjs", - "require": "./handlers/next-edge/index.js" + "./handlers/fetch-api": { + "types": "./handlers/fetch-api/index.d.ts", + "import": "./handlers/fetch-api/index.mjs", + "require": "./handlers/fetch-api/index.js" + }, + "./handlers/shared": { + "types": "./handlers/shared/index.d.ts", + "import": "./handlers/shared/index.mjs", + "require": "./handlers/shared/index.js" }, "./saleor-app": { "types": "./saleor-app.d.ts", From 9e5c059655fa237b521bd7cb24a97e2f7cc2f539 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Thu, 2 Jan 2025 16:42:59 +0100 Subject: [PATCH 17/58] Add webhook handlers --- .../fetch-api/process-protected-handler.ts | 2 +- .../saleor-webhooks/process-saleor-webhook.ts | 162 +++++++++++++++ .../saleor-webhooks/saleor-async-webhook.ts | 48 +++++ .../saleor-webhooks/saleor-sync-webhook.ts | 36 ++++ .../saleor-webhooks/saleor-webhook.ts | 184 ++++++++++++++++++ src/handlers/next/index.ts | 2 +- .../saleor-webhooks/process-saleor-webhook.ts | 39 +--- .../saleor-webhooks/saleor-sync-webhook.ts | 2 +- .../next/saleor-webhooks/saleor-webhook.ts | 26 +-- src/handlers/shared/process-saleor-webhook.ts | 38 ++++ src/handlers/shared/saleor-webhook.ts | 18 ++ .../sync-webhook-response-builder.ts | 2 +- 12 files changed, 494 insertions(+), 65 deletions(-) create mode 100644 src/handlers/fetch-api/saleor-webhooks/process-saleor-webhook.ts create mode 100644 src/handlers/fetch-api/saleor-webhooks/saleor-async-webhook.ts create mode 100644 src/handlers/fetch-api/saleor-webhooks/saleor-sync-webhook.ts create mode 100644 src/handlers/fetch-api/saleor-webhooks/saleor-webhook.ts create mode 100644 src/handlers/shared/process-saleor-webhook.ts create mode 100644 src/handlers/shared/saleor-webhook.ts rename src/handlers/{next/saleor-webhooks => shared}/sync-webhook-response-builder.ts (98%) diff --git a/src/handlers/fetch-api/process-protected-handler.ts b/src/handlers/fetch-api/process-protected-handler.ts index 447298a2..5e7ddc57 100644 --- a/src/handlers/fetch-api/process-protected-handler.ts +++ b/src/handlers/fetch-api/process-protected-handler.ts @@ -9,7 +9,7 @@ import { extractUserFromJwt } from "../../util/extract-user-from-jwt"; import { verifyJWT } from "../../verify-jwt"; import { ProtectedHandlerContext } from "../shared/protected-handler-context"; -const debug = createDebug("processProtectedHandler"); +const debug = createDebug("WebAPI:processProtectedHandler"); export type SaleorProtectedHandlerError = | "OTHER" diff --git a/src/handlers/fetch-api/saleor-webhooks/process-saleor-webhook.ts b/src/handlers/fetch-api/saleor-webhooks/process-saleor-webhook.ts new file mode 100644 index 00000000..ac69ed5f --- /dev/null +++ b/src/handlers/fetch-api/saleor-webhooks/process-saleor-webhook.ts @@ -0,0 +1,162 @@ +import { APL } from "../../../APL"; +import { createDebug } from "../../../debug"; +import { fetchRemoteJwks } from "../../../fetch-remote-jwks"; +import { getBaseUrlFetchAPI, getSaleorHeadersFetchAPI } from "../../../headers"; +import { parseSchemaVersion } from "../../../util"; +import { verifySignatureWithJwks } from "../../../verify-signature"; +import { WebhookContext, WebhookError } from "../../shared/process-saleor-webhook"; + +const debug = createDebug("WebAPI:processSaleorWebhook"); + +interface ProcessSaleorWebhookArgs { + req: Request; + apl: APL; + allowedEvent: string; +} + +export const processSaleorWebhook = async ({ + req, + apl, + allowedEvent, +}: ProcessSaleorWebhookArgs): Promise> => { + // TODO: Add OTEL + + try { + debug("Request processing started"); + + if (req.method !== "POST") { + debug("Wrong HTTP method"); + throw new WebhookError("Wrong request method, only POST allowed", "WRONG_METHOD"); + } + + const { event, signature, saleorApiUrl } = getSaleorHeadersFetchAPI(req.headers); + const baseUrl = getBaseUrlFetchAPI(req.headers); + + if (!baseUrl) { + debug("Missing host header"); + throw new WebhookError("Missing host header", "MISSING_HOST_HEADER"); + } + + if (!saleorApiUrl) { + debug("Missing saleor-api-url header"); + throw new WebhookError("Missing saleor-api-url header", "MISSING_API_URL_HEADER"); + } + + if (!event) { + debug("Missing saleor-event header"); + throw new WebhookError("Missing saleor-event header", "MISSING_EVENT_HEADER"); + } + + const expected = allowedEvent.toLowerCase(); + + if (event !== expected) { + debug(`Wrong incoming request event: ${event}. Expected: ${expected}`); + + throw new WebhookError( + `Wrong incoming request event: ${event}. Expected: ${expected}`, + "WRONG_EVENT" + ); + } + + if (!signature) { + debug("No signature"); + + throw new WebhookError("Missing saleor-signature header", "MISSING_SIGNATURE_HEADER"); + } + + let rawBody: string; + + try { + rawBody = await req.text(); + } catch (err) { + throw new WebhookError("Error reading request body", "CANT_BE_PARSED"); + } + + if (!rawBody) { + debug("Missing request body"); + + throw new WebhookError("Missing request body", "MISSING_REQUEST_BODY"); + } + + let parsedBody: unknown & { version?: string | null }; + + try { + parsedBody = JSON.parse(rawBody); + } catch (err) { + throw new WebhookError("Request body can't be parsed", "CANT_BE_PARSED"); + } + + let parsedSchemaVersion: number | null = null; + + try { + parsedSchemaVersion = parseSchemaVersion(parsedBody.version); + } catch { + debug("Schema version cannot be parsed"); + } + + /** + * Verify if the app is properly installed for given Saleor API URL + */ + const authData = await apl.get(saleorApiUrl); + + if (!authData) { + debug("APL didn't found auth data for %s", saleorApiUrl); + + throw new WebhookError( + `Can't find auth data for ${saleorApiUrl}. Please register the application`, + "NOT_REGISTERED" + ); + } + + /** + * Verify payload signature + * + * TODO: Add test for repeat verification scenario + */ + try { + debug("Will verify signature with JWKS saved in AuthData"); + + if (!authData.jwks) { + throw new Error("JWKS not found in AuthData"); + } + + await verifySignatureWithJwks(authData.jwks, signature, rawBody); + } catch { + debug("Request signature check failed. Refresh the JWKS cache and check again"); + + const newJwks = await fetchRemoteJwks(authData.saleorApiUrl).catch((e) => { + debug(e); + + throw new WebhookError("Fetching remote JWKS failed", "SIGNATURE_VERIFICATION_FAILED"); + }); + + debug("Fetched refreshed JWKS"); + + try { + debug("Second attempt to validate the signature JWKS, using fresh tokens from the API"); + + await verifySignatureWithJwks(newJwks, signature, rawBody); + + debug("Verification successful - update JWKS in the AuthData"); + + await apl.set({ ...authData, jwks: newJwks }); + } catch { + debug("Second attempt also ended with validation error. Reject the webhook"); + + throw new WebhookError("Request signature check failed", "SIGNATURE_VERIFICATION_FAILED"); + } + } + + return { + baseUrl, + event, + payload: parsedBody as T, + authData, + schemaVersion: parsedSchemaVersion, + }; + } catch (err) { + debug("Unexpected error: %O", err); + + throw err; + } +}; diff --git a/src/handlers/fetch-api/saleor-webhooks/saleor-async-webhook.ts b/src/handlers/fetch-api/saleor-webhooks/saleor-async-webhook.ts new file mode 100644 index 00000000..181ec4bc --- /dev/null +++ b/src/handlers/fetch-api/saleor-webhooks/saleor-async-webhook.ts @@ -0,0 +1,48 @@ +import { ASTNode } from "graphql"; + +import { AsyncWebhookEventType } from "../../../types"; +import { SaleorWebApiWebhook, WebApiWebhookHandler, WebhookConfig } from "./saleor-webhook"; + +export class SaleorAsyncWebhook extends SaleorWebApiWebhook { + readonly event: AsyncWebhookEventType; + + protected readonly eventType = "async" as const; + + constructor( + /** + * Omit new required fields and make them optional. Validate in constructor. + * In 0.35.0 remove old fields + */ + configuration: Omit, "event" | "query"> & { + /** + * @deprecated - use `event` instead. Will be removed in 0.35.0 + */ + asyncEvent?: AsyncWebhookEventType; + event?: AsyncWebhookEventType; + query?: string | ASTNode; + } + ) { + if (!configuration.event && !configuration.asyncEvent) { + throw new Error("event or asyncEvent must be provided. asyncEvent is deprecated"); + } + + if (!configuration.query && !configuration.subscriptionQueryAst) { + throw new Error( + "query or subscriptionQueryAst must be provided. subscriptionQueryAst is deprecated" + ); + } + + super({ + ...configuration, + event: configuration.event! ?? configuration.asyncEvent!, + query: configuration.query! ?? configuration.subscriptionQueryAst!, + }); + + this.event = configuration.event! ?? configuration.asyncEvent!; + this.query = configuration.query! ?? configuration.subscriptionQueryAst!; + } + + createHandler(handlerFn: WebApiWebhookHandler): WebApiWebhookHandler { + return super.createHandler(handlerFn); + } +} diff --git a/src/handlers/fetch-api/saleor-webhooks/saleor-sync-webhook.ts b/src/handlers/fetch-api/saleor-webhooks/saleor-sync-webhook.ts new file mode 100644 index 00000000..c880f82b --- /dev/null +++ b/src/handlers/fetch-api/saleor-webhooks/saleor-sync-webhook.ts @@ -0,0 +1,36 @@ +import { SyncWebhookEventType } from "../../../types"; +import { buildSyncWebhookResponsePayload } from "../../shared/sync-webhook-response-builder"; +import { SaleorWebApiWebhook, WebApiWebhookHandler, WebhookConfig } from "./saleor-webhook"; + +type InjectedContext = { + buildResponse: typeof buildSyncWebhookResponsePayload; +}; +export class SaleorSyncWebhook< + TPayload = unknown, + TEvent extends SyncWebhookEventType = SyncWebhookEventType +> extends SaleorWebApiWebhook> { + readonly event: TEvent; + + protected readonly eventType = "sync" as const; + + protected extraContext = { + buildResponse: buildSyncWebhookResponsePayload, + }; + + constructor(configuration: WebhookConfig) { + super(configuration); + + this.event = configuration.event; + } + + createHandler( + handlerFn: WebApiWebhookHandler< + TPayload, + { + buildResponse: typeof buildSyncWebhookResponsePayload; + } + > + ): WebApiWebhookHandler { + return super.createHandler(handlerFn); + } +} diff --git a/src/handlers/fetch-api/saleor-webhooks/saleor-webhook.ts b/src/handlers/fetch-api/saleor-webhooks/saleor-webhook.ts new file mode 100644 index 00000000..1d8e3785 --- /dev/null +++ b/src/handlers/fetch-api/saleor-webhooks/saleor-webhook.ts @@ -0,0 +1,184 @@ +import { ASTNode } from "graphql"; + +import { APL } from "../../../APL"; +import { createDebug } from "../../../debug"; +import { gqlAstToString } from "../../../gql-ast-to-string"; +import { AsyncWebhookEventType, SyncWebhookEventType, WebhookManifest } from "../../../types"; +import { WebhookContext, WebhookError } from "../../shared/process-saleor-webhook"; +import { WebhookErrorCodeMap } from "../../shared/saleor-webhook"; +import { processSaleorWebhook } from "./process-saleor-webhook"; + +const debug = createDebug("SaleorWebhook"); + +export interface WebhookConfig { + name?: string; + webhookPath: string; + event: Event; + isActive?: boolean; + apl: APL; + onError?(error: WebhookError | Error, request: Request): void; + formatErrorResponse?( + error: WebhookError | Error, + request: Request + ): Promise<{ + code: number; + body: string; + }>; + query: string | ASTNode; + /** + * @deprecated will be removed in 0.35.0, use query field instead + */ + subscriptionQueryAst?: ASTNode; +} + +export type WebApiWebhookHandler = ( + req: Request, + ctx: WebhookContext & TExtras +) => unknown | Promise; + +export abstract class SaleorWebApiWebhook< + TPayload = unknown, + TExtras extends Record = {} +> { + protected abstract eventType: "async" | "sync"; + + protected extraContext?: TExtras; + + name: string; + + webhookPath: string; + + query: string | ASTNode; + + event: AsyncWebhookEventType | SyncWebhookEventType; + + isActive?: boolean; + + apl: APL; + + onError: WebhookConfig["onError"]; + + formatErrorResponse: WebhookConfig["formatErrorResponse"]; + + protected constructor(configuration: WebhookConfig) { + const { + name, + webhookPath, + event, + query, + apl, + isActive = true, + subscriptionQueryAst, + } = configuration; + + this.name = name || `${event} webhook`; + /** + * Fallback subscriptionQueryAst to avoid breaking changes + * + * TODO Remove in 0.35.0 + */ + this.query = query ?? subscriptionQueryAst; + this.webhookPath = webhookPath; + this.event = event; + this.isActive = isActive; + this.apl = apl; + this.onError = configuration.onError; + this.formatErrorResponse = configuration.formatErrorResponse; + } + + private getTargetUrl(baseUrl: string) { + return new URL(this.webhookPath, baseUrl).href; + } + + /** + * Returns synchronous event manifest for this webhook. + * + * @param baseUrl Base URL used by your application + * @returns WebhookManifest + */ + getWebhookManifest(baseUrl: string): WebhookManifest { + const manifestBase: Omit = { + query: typeof this.query === "string" ? this.query : gqlAstToString(this.query), + name: this.name, + targetUrl: this.getTargetUrl(baseUrl), + isActive: this.isActive, + }; + + switch (this.eventType) { + case "async": + return { + ...manifestBase, + asyncEvents: [this.event as AsyncWebhookEventType], + }; + case "sync": + return { + ...manifestBase, + syncEvents: [this.event as SyncWebhookEventType], + }; + default: { + throw new Error("Class extended incorrectly"); + } + } + } + + /** + * Wraps provided function, to ensure incoming request comes from registered Saleor instance. + * Also provides additional `context` object containing typed payload and request properties. + */ + createHandler(handlerFn: WebApiWebhookHandler): WebApiWebhookHandler { + return async (req) => { + debug(`Handler for webhook ${this.name} called`); + + await processSaleorWebhook({ + req, + apl: this.apl, + allowedEvent: this.event, + }) + .then(async (context) => { + debug("Incoming request validated. Call handlerFn"); + + return handlerFn(req, { ...(this.extraContext ?? ({} as TExtras)), ...context }); + }) + .catch(async (e) => { + debug(`Unexpected error during processing the webhook ${this.name}`); + + if (e instanceof WebhookError) { + debug(`Validation error: ${e.message}`); + + if (this.onError) { + this.onError(e, req); + } + + if (this.formatErrorResponse) { + const { code, body } = await this.formatErrorResponse(e, req); + + return new Response(body, { status: code }); + } + + return new Response( + JSON.stringify({ + error: { + type: e.errorType, + message: e.message, + }, + }), + { status: WebhookErrorCodeMap[e.errorType] || 400 } + ); + } + debug("Unexpected error: %O", e); + + if (this.onError) { + this.onError(e, req); + } + + if (this.formatErrorResponse) { + const { code, body } = await this.formatErrorResponse(e, req); + + return new Response(body, { status: code }); + } + + return new Response("Unexpected error while handling request", { status: 500 }); + }); + }; + } +} diff --git a/src/handlers/next/index.ts b/src/handlers/next/index.ts index cd407d00..5480b408 100644 --- a/src/handlers/next/index.ts +++ b/src/handlers/next/index.ts @@ -1,5 +1,6 @@ // Re-export to avoid breaking changes export * from "../shared/protected-handler-context"; +export * from "../shared/sync-webhook-response-builder"; export * from "./create-app-register-handler"; export * from "./create-manifest-handler"; export * from "./create-protected-handler"; @@ -7,4 +8,3 @@ export * from "./process-protected-handler"; export * from "./saleor-webhooks/saleor-async-webhook"; export * from "./saleor-webhooks/saleor-sync-webhook"; export { NextWebhookApiHandler } from "./saleor-webhooks/saleor-webhook"; -export * from "./saleor-webhooks/sync-webhook-response-builder"; diff --git a/src/handlers/next/saleor-webhooks/process-saleor-webhook.ts b/src/handlers/next/saleor-webhooks/process-saleor-webhook.ts index a6451802..237e93df 100644 --- a/src/handlers/next/saleor-webhooks/process-saleor-webhook.ts +++ b/src/handlers/next/saleor-webhooks/process-saleor-webhook.ts @@ -3,53 +3,16 @@ import { NextApiRequest } from "next"; import getRawBody from "raw-body"; import { APL } from "../../../APL"; -import { AuthData } from "../../../APL/apl"; import { createDebug } from "../../../debug"; import { fetchRemoteJwks } from "../../../fetch-remote-jwks"; import { getBaseUrl, getSaleorHeaders } from "../../../headers"; import { getOtelTracer } from "../../../open-telemetry"; import { parseSchemaVersion } from "../../../util"; import { verifySignatureWithJwks } from "../../../verify-signature"; +import { WebhookContext, WebhookError } from "../../shared/process-saleor-webhook"; const debug = createDebug("processSaleorWebhook"); -export type SaleorWebhookError = - | "OTHER" - | "MISSING_HOST_HEADER" - | "MISSING_DOMAIN_HEADER" - | "MISSING_API_URL_HEADER" - | "MISSING_EVENT_HEADER" - | "MISSING_PAYLOAD_HEADER" - | "MISSING_SIGNATURE_HEADER" - | "MISSING_REQUEST_BODY" - | "WRONG_EVENT" - | "NOT_REGISTERED" - | "SIGNATURE_VERIFICATION_FAILED" - | "WRONG_METHOD" - | "CANT_BE_PARSED" - | "CONFIGURATION_ERROR"; - -export class WebhookError extends Error { - errorType: SaleorWebhookError = "OTHER"; - - constructor(message: string, errorType: SaleorWebhookError) { - super(message); - if (errorType) { - this.errorType = errorType; - } - Object.setPrototypeOf(this, WebhookError.prototype); - } -} - -export type WebhookContext = { - baseUrl: string; - event: string; - payload: T; - authData: AuthData; - /** For Saleor < 3.15 it will be null. */ - schemaVersion: number | null; -}; - interface ProcessSaleorWebhookArgs { req: NextApiRequest; apl: APL; diff --git a/src/handlers/next/saleor-webhooks/saleor-sync-webhook.ts b/src/handlers/next/saleor-webhooks/saleor-sync-webhook.ts index 3ab6b63f..79f75220 100644 --- a/src/handlers/next/saleor-webhooks/saleor-sync-webhook.ts +++ b/src/handlers/next/saleor-webhooks/saleor-sync-webhook.ts @@ -1,8 +1,8 @@ import { NextApiHandler } from "next"; import { SyncWebhookEventType } from "../../../types"; +import { buildSyncWebhookResponsePayload } from "../../shared/sync-webhook-response-builder"; import { NextWebhookApiHandler, SaleorWebhook, WebhookConfig } from "./saleor-webhook"; -import { buildSyncWebhookResponsePayload } from "./sync-webhook-response-builder"; type InjectedContext = { buildResponse: typeof buildSyncWebhookResponsePayload; diff --git a/src/handlers/next/saleor-webhooks/saleor-webhook.ts b/src/handlers/next/saleor-webhooks/saleor-webhook.ts index 9a0d7632..3fbf1561 100644 --- a/src/handlers/next/saleor-webhooks/saleor-webhook.ts +++ b/src/handlers/next/saleor-webhooks/saleor-webhook.ts @@ -5,12 +5,9 @@ import { APL } from "../../../APL"; import { createDebug } from "../../../debug"; import { gqlAstToString } from "../../../gql-ast-to-string"; import { AsyncWebhookEventType, SyncWebhookEventType, WebhookManifest } from "../../../types"; -import { - processSaleorWebhook, - SaleorWebhookError, - WebhookContext, - WebhookError, -} from "./process-saleor-webhook"; +import { WebhookContext, WebhookError } from "../../shared/process-saleor-webhook"; +import { WebhookErrorCodeMap } from "../../shared/saleor-webhook"; +import { processSaleorWebhook } from "./process-saleor-webhook"; const debug = createDebug("SaleorWebhook"); @@ -36,23 +33,6 @@ export interface WebhookConfig = { - OTHER: 500, - MISSING_HOST_HEADER: 400, - MISSING_DOMAIN_HEADER: 400, - MISSING_API_URL_HEADER: 400, - MISSING_EVENT_HEADER: 400, - MISSING_PAYLOAD_HEADER: 400, - MISSING_SIGNATURE_HEADER: 400, - MISSING_REQUEST_BODY: 400, - WRONG_EVENT: 400, - NOT_REGISTERED: 401, - SIGNATURE_VERIFICATION_FAILED: 401, - WRONG_METHOD: 405, - CANT_BE_PARSED: 400, - CONFIGURATION_ERROR: 500, -}; - export type NextWebhookApiHandler = ( req: NextApiRequest, res: NextApiResponse, diff --git a/src/handlers/shared/process-saleor-webhook.ts b/src/handlers/shared/process-saleor-webhook.ts new file mode 100644 index 00000000..ba36e913 --- /dev/null +++ b/src/handlers/shared/process-saleor-webhook.ts @@ -0,0 +1,38 @@ +import { AuthData } from "../../APL"; + +export type SaleorWebhookError = + | "OTHER" + | "MISSING_HOST_HEADER" + | "MISSING_DOMAIN_HEADER" + | "MISSING_API_URL_HEADER" + | "MISSING_EVENT_HEADER" + | "MISSING_PAYLOAD_HEADER" + | "MISSING_SIGNATURE_HEADER" + | "MISSING_REQUEST_BODY" + | "WRONG_EVENT" + | "NOT_REGISTERED" + | "SIGNATURE_VERIFICATION_FAILED" + | "WRONG_METHOD" + | "CANT_BE_PARSED" + | "CONFIGURATION_ERROR"; + +export class WebhookError extends Error { + errorType: SaleorWebhookError = "OTHER"; + + constructor(message: string, errorType: SaleorWebhookError) { + super(message); + if (errorType) { + this.errorType = errorType; + } + Object.setPrototypeOf(this, WebhookError.prototype); + } +} + +export type WebhookContext = { + baseUrl: string; + event: string; + payload: T; + authData: AuthData; + /** For Saleor < 3.15 it will be null. */ + schemaVersion: number | null; +}; diff --git a/src/handlers/shared/saleor-webhook.ts b/src/handlers/shared/saleor-webhook.ts new file mode 100644 index 00000000..935da295 --- /dev/null +++ b/src/handlers/shared/saleor-webhook.ts @@ -0,0 +1,18 @@ +import { SaleorWebhookError } from "./process-saleor-webhook"; + +export const WebhookErrorCodeMap: Record = { + OTHER: 500, + MISSING_HOST_HEADER: 400, + MISSING_DOMAIN_HEADER: 400, + MISSING_API_URL_HEADER: 400, + MISSING_EVENT_HEADER: 400, + MISSING_PAYLOAD_HEADER: 400, + MISSING_SIGNATURE_HEADER: 400, + MISSING_REQUEST_BODY: 400, + WRONG_EVENT: 400, + NOT_REGISTERED: 401, + SIGNATURE_VERIFICATION_FAILED: 401, + WRONG_METHOD: 405, + CANT_BE_PARSED: 400, + CONFIGURATION_ERROR: 500, +}; diff --git a/src/handlers/next/saleor-webhooks/sync-webhook-response-builder.ts b/src/handlers/shared/sync-webhook-response-builder.ts similarity index 98% rename from src/handlers/next/saleor-webhooks/sync-webhook-response-builder.ts rename to src/handlers/shared/sync-webhook-response-builder.ts index 952e0cb7..9b690661 100644 --- a/src/handlers/next/saleor-webhooks/sync-webhook-response-builder.ts +++ b/src/handlers/shared/sync-webhook-response-builder.ts @@ -1,4 +1,4 @@ -import { SyncWebhookEventType } from "../../../types"; +import { SyncWebhookEventType } from "../../types"; export type SyncWebhookResponsesMap = { CHECKOUT_CALCULATE_TAXES: { From 98ace2238984c9237a885fbd7a1b936aa47a1126 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 3 Jan 2025 13:41:23 +0100 Subject: [PATCH 18/58] Export missing functions, fix errors when handling Web api webhooks --- src/handlers/fetch-api/index.ts | 5 ++--- src/handlers/fetch-api/saleor-webhooks/saleor-webhook.ts | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/handlers/fetch-api/index.ts b/src/handlers/fetch-api/index.ts index 42f05125..3bc2ff5a 100644 --- a/src/handlers/fetch-api/index.ts +++ b/src/handlers/fetch-api/index.ts @@ -2,6 +2,5 @@ export * from "./create-app-register-handler"; export * from "./create-manifest-handler"; export * from "./create-protected-handler"; export * from "./process-protected-handler"; -// export * from "./saleor-webhooks/saleor-async-webhook"; -// export * from "./saleor-webhooks/saleor-sync-webhook"; -// export * from "./saleor-webhooks/sync-webhook-response-builder"; +export * from "./saleor-webhooks/saleor-async-webhook"; +export * from "./saleor-webhooks/saleor-sync-webhook"; diff --git a/src/handlers/fetch-api/saleor-webhooks/saleor-webhook.ts b/src/handlers/fetch-api/saleor-webhooks/saleor-webhook.ts index 1d8e3785..f4f7119d 100644 --- a/src/handlers/fetch-api/saleor-webhooks/saleor-webhook.ts +++ b/src/handlers/fetch-api/saleor-webhooks/saleor-webhook.ts @@ -129,7 +129,7 @@ export abstract class SaleorWebApiWebhook< return async (req) => { debug(`Handler for webhook ${this.name} called`); - await processSaleorWebhook({ + return processSaleorWebhook({ req, apl: this.apl, allowedEvent: this.event, From 1b87494f9bfd510e005902a4c377af515a9e1d21 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Thu, 9 Jan 2025 16:03:08 +0100 Subject: [PATCH 19/58] Fix web api webhook typing --- .../fetch-api/saleor-webhooks/saleor-async-webhook.ts | 9 +++++++-- .../fetch-api/saleor-webhooks/saleor-sync-webhook.ts | 11 ++++++++--- .../fetch-api/saleor-webhooks/saleor-webhook.ts | 10 +++++++--- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/handlers/fetch-api/saleor-webhooks/saleor-async-webhook.ts b/src/handlers/fetch-api/saleor-webhooks/saleor-async-webhook.ts index 181ec4bc..71a191cb 100644 --- a/src/handlers/fetch-api/saleor-webhooks/saleor-async-webhook.ts +++ b/src/handlers/fetch-api/saleor-webhooks/saleor-async-webhook.ts @@ -1,7 +1,12 @@ import { ASTNode } from "graphql"; import { AsyncWebhookEventType } from "../../../types"; -import { SaleorWebApiWebhook, WebApiWebhookHandler, WebhookConfig } from "./saleor-webhook"; +import { + SaleorWebApiWebhook, + SaleorWebhookHandler, + WebApiRouteHandler, + WebhookConfig, +} from "./saleor-webhook"; export class SaleorAsyncWebhook extends SaleorWebApiWebhook { readonly event: AsyncWebhookEventType; @@ -42,7 +47,7 @@ export class SaleorAsyncWebhook extends SaleorWebApiWebhook< this.query = configuration.query! ?? configuration.subscriptionQueryAst!; } - createHandler(handlerFn: WebApiWebhookHandler): WebApiWebhookHandler { + createHandler(handlerFn: SaleorWebhookHandler): WebApiRouteHandler { return super.createHandler(handlerFn); } } diff --git a/src/handlers/fetch-api/saleor-webhooks/saleor-sync-webhook.ts b/src/handlers/fetch-api/saleor-webhooks/saleor-sync-webhook.ts index c880f82b..d3cc2e5a 100644 --- a/src/handlers/fetch-api/saleor-webhooks/saleor-sync-webhook.ts +++ b/src/handlers/fetch-api/saleor-webhooks/saleor-sync-webhook.ts @@ -1,6 +1,11 @@ import { SyncWebhookEventType } from "../../../types"; import { buildSyncWebhookResponsePayload } from "../../shared/sync-webhook-response-builder"; -import { SaleorWebApiWebhook, WebApiWebhookHandler, WebhookConfig } from "./saleor-webhook"; +import { + SaleorWebApiWebhook, + SaleorWebhookHandler, + WebApiRouteHandler, + WebhookConfig, +} from "./saleor-webhook"; type InjectedContext = { buildResponse: typeof buildSyncWebhookResponsePayload; @@ -24,13 +29,13 @@ export class SaleorSyncWebhook< } createHandler( - handlerFn: WebApiWebhookHandler< + handlerFn: SaleorWebhookHandler< TPayload, { buildResponse: typeof buildSyncWebhookResponsePayload; } > - ): WebApiWebhookHandler { + ): WebApiRouteHandler { return super.createHandler(handlerFn); } } diff --git a/src/handlers/fetch-api/saleor-webhooks/saleor-webhook.ts b/src/handlers/fetch-api/saleor-webhooks/saleor-webhook.ts index f4f7119d..9d5a1709 100644 --- a/src/handlers/fetch-api/saleor-webhooks/saleor-webhook.ts +++ b/src/handlers/fetch-api/saleor-webhooks/saleor-webhook.ts @@ -31,10 +31,14 @@ export interface WebhookConfig = ( +/** Generic Web API route handler */ +export type WebApiRouteHandler = (request: Request) => Response | Promise; + +/** Function type provided by consumer in `SaleorWebApiWebhook.createHandler` */ +export type SaleorWebhookHandler = ( req: Request, ctx: WebhookContext & TExtras -) => unknown | Promise; +) => Response | Promise; export abstract class SaleorWebApiWebhook< TPayload = unknown, @@ -125,7 +129,7 @@ export abstract class SaleorWebApiWebhook< * Wraps provided function, to ensure incoming request comes from registered Saleor instance. * Also provides additional `context` object containing typed payload and request properties. */ - createHandler(handlerFn: WebApiWebhookHandler): WebApiWebhookHandler { + createHandler(handlerFn: SaleorWebhookHandler): WebApiRouteHandler { return async (req) => { debug(`Handler for webhook ${this.name} called`); From d5e8785ff04516ebc898bf00ce049334f0b8ac33 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 10 Jan 2025 18:32:06 +0100 Subject: [PATCH 20/58] Add fallback for Request.url.protocol --- .../fetch-api/create-manifest-handler.ts | 2 +- .../fetch-api/process-protected-handler.ts | 4 +-- .../saleor-webhooks/process-saleor-webhook.ts | 2 +- src/headers.ts | 27 +++++++++++++++---- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/handlers/fetch-api/create-manifest-handler.ts b/src/handlers/fetch-api/create-manifest-handler.ts index 22f28a85..fe554a76 100644 --- a/src/handlers/fetch-api/create-manifest-handler.ts +++ b/src/handlers/fetch-api/create-manifest-handler.ts @@ -13,7 +13,7 @@ export type CreateManifestHandlerOptions = { export const createManifestHandler = (options: CreateManifestHandlerOptions) => async (request: Request) => { const { schemaVersion } = getSaleorHeadersFetchAPI(request.headers); - const baseURL = getBaseUrlFetchAPI(request.headers); + const baseURL = getBaseUrlFetchAPI(request); const manifest = await options.manifestFactory({ appBaseUrl: baseURL, diff --git a/src/handlers/fetch-api/process-protected-handler.ts b/src/handlers/fetch-api/process-protected-handler.ts index 5e7ddc57..8edb38e5 100644 --- a/src/handlers/fetch-api/process-protected-handler.ts +++ b/src/handlers/fetch-api/process-protected-handler.ts @@ -34,7 +34,7 @@ export class ProtectedHandlerError extends Error { } interface ProcessSaleorProtectedHandlerArgs { - request: Pick; + request: Request; apl: APL; requiredPermissions?: Permission[]; } @@ -71,7 +71,7 @@ export const processSaleorProtectedHandler: ProcessAsyncSaleorProtectedHandler = request.headers ); - const baseUrl = getBaseUrlFetchAPI(request.headers); + const baseUrl = getBaseUrlFetchAPI(request); span.setAttribute("saleorApiUrl", saleorApiUrl ?? ""); diff --git a/src/handlers/fetch-api/saleor-webhooks/process-saleor-webhook.ts b/src/handlers/fetch-api/saleor-webhooks/process-saleor-webhook.ts index ac69ed5f..528642a4 100644 --- a/src/handlers/fetch-api/saleor-webhooks/process-saleor-webhook.ts +++ b/src/handlers/fetch-api/saleor-webhooks/process-saleor-webhook.ts @@ -30,7 +30,7 @@ export const processSaleorWebhook = async ({ } const { event, signature, saleorApiUrl } = getSaleorHeadersFetchAPI(req.headers); - const baseUrl = getBaseUrlFetchAPI(req.headers); + const baseUrl = getBaseUrlFetchAPI(req); if (!baseUrl) { debug("Missing host header"); diff --git a/src/headers.ts b/src/headers.ts index 0bcec654..b6d91c6a 100644 --- a/src/headers.ts +++ b/src/headers.ts @@ -50,12 +50,29 @@ export const getBaseUrl = (headers: { [name: string]: string | string[] | undefi return `${protocol}://${host}`; }; -export const getBaseUrlFetchAPI = (headers: Headers) => { - const host = headers.get("host"); - const xForwardedProto = headers.get("x-forwarded-proto") || "http"; +export const getBaseUrlFetchAPI = (request: Request) => { + let url: URL | undefined; + try { + url = new URL(request.url); + } catch (e) { + // no-op + } - const protocols = xForwardedProto.split(",").map((value) => value.trimStart()); - const protocol = protocols.find((el) => el === "https") || protocols[0]; + const host = request.headers.get("host"); + const xForwardedProto = request.headers.get("x-forwarded-proto"); + + let protocol: string; + if (xForwardedProto) { + const xForwardedForProtocols = xForwardedProto.split(",").map((value) => value.trimStart()); + protocol = xForwardedForProtocols.find((el) => el === "https") || xForwardedForProtocols[0]; + } else if (url) { + // Some providers (e.g. Deno Deploy) + // do not set x-forwarded-for header when handling request + // try to get it from URL + protocol = url.protocol.replace(":", ""); + } else { + protocol = "http"; + } return `${protocol}://${host}`; }; From 32bec65cdef6e854e48858ec9542d6887d04cb44 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Tue, 14 Jan 2025 18:51:20 +0100 Subject: [PATCH 21/58] Refactor handler into use case and adapters --- .../fetch-api/create-app-register-handler.ts | 241 +------------ src/handlers/fetch-api/platform-adapter.ts | 47 +++ .../next/create-app-register-handler.ts | 238 +------------ src/handlers/next/platform-adapter.ts | 39 +++ .../shared/generic-adapter-use-case-types.ts | 40 +++ src/handlers/shared/manifest-use-case.ts | 318 ++++++++++++++++++ 6 files changed, 469 insertions(+), 454 deletions(-) create mode 100644 src/handlers/fetch-api/platform-adapter.ts create mode 100644 src/handlers/next/platform-adapter.ts create mode 100644 src/handlers/shared/generic-adapter-use-case-types.ts create mode 100644 src/handlers/shared/manifest-use-case.ts diff --git a/src/handlers/fetch-api/create-app-register-handler.ts b/src/handlers/fetch-api/create-app-register-handler.ts index 2d96c062..5af52134 100644 --- a/src/handlers/fetch-api/create-app-register-handler.ts +++ b/src/handlers/fetch-api/create-app-register-handler.ts @@ -1,36 +1,6 @@ -import { SALEOR_API_URL_HEADER, SALEOR_DOMAIN_HEADER } from "../../const"; -import { createDebug } from "../../debug"; -import { toRequestHandler } from "../../fetch-middleware/to-request-handler"; -import { FetchHandler } from "../../fetch-middleware/types"; -import { withAuthTokenRequired } from "../../fetch-middleware/with-auth-token-required"; -import { withMethod } from "../../fetch-middleware/with-method"; -import { withSaleorDomainPresent } from "../../fetch-middleware/with-saleor-domain-present"; -import { fetchRemoteJwks } from "../../fetch-remote-jwks"; -import { getAppId } from "../../get-app-id"; -import { - CallbackErrorHandler, - GenericCreateAppRegisterHandlerOptions, - HookCallbackErrorParams, -} from "../shared/create-app-register-handler-types"; -import { validateAllowSaleorUrls } from "../shared/validate-allow-saleor-urls"; - -const debug = createDebug("WebApi:createAppRegisterHandler"); - -class RegisterCallbackError extends Error { - public status = 500; - - constructor(errorParams: HookCallbackErrorParams) { - super(errorParams.message); - - if (errorParams.status) { - this.status = errorParams.status; - } - } -} - -const createCallbackError: CallbackErrorHandler = (params: HookCallbackErrorParams) => { - throw new RegisterCallbackError(params); -}; +import { GenericCreateAppRegisterHandlerOptions } from "../shared/create-app-register-handler-types"; +import { ManifestUseCase } from "../shared/manifest-use-case"; +import { WebApiAdapter, WebApiHandler, WebApiHandlerInput } from "./platform-adapter"; export type RegisterHandlerResponseBody = { success: boolean; @@ -48,201 +18,14 @@ export const createRegisterHandlerResponseBody = ( error, }); -const handleHookError = (e: RegisterCallbackError | unknown) => { - if (e instanceof RegisterCallbackError) { - return Response.json( - createRegisterHandlerResponseBody(false, { - code: "REGISTER_HANDLER_HOOK_ERROR", - message: e.message, - }), - { status: e.status } - ); - } - return new Response("Error during app installation", { status: 500 }); -}; - -// Request type is from Web API -export type CreateAppRegisterHandlerOptions = GenericCreateAppRegisterHandlerOptions; - -/** - * Creates API handler for Next.js. Creates handler called by Saleor that registers app. - * Hides implementation details if possible - * In the future this will be extracted to separate sdk/next package - */ -export const createAppRegisterHandler = ({ - apl, - allowedSaleorUrls, - onAplSetFailed, - onAuthAplSaved, - onRequestVerified, - onRequestStart, -}: CreateAppRegisterHandlerOptions) => { - const baseHandler: FetchHandler = async (inputRequest) => { - debug("Request received"); - - const request = inputRequest.clone(); - const json = await request.json(); - const authToken = json.auth_token; - const saleorDomain = request.headers.get(SALEOR_DOMAIN_HEADER) as string; - const saleorApiUrl = request.headers.get(SALEOR_API_URL_HEADER) as string; - - if (onRequestStart) { - debug("Calling \"onRequestStart\" hook"); - - try { - await onRequestStart(request, { - authToken, - saleorApiUrl, - saleorDomain, - respondWithError: createCallbackError, - }); - } catch (e: RegisterCallbackError | unknown) { - debug("\"onRequestStart\" hook thrown error: %o", e); - - return handleHookError(e); - } - } - - if (!saleorApiUrl) { - debug("saleorApiUrl doesn't exist in headers"); - } - - if (!validateAllowSaleorUrls(saleorApiUrl, allowedSaleorUrls)) { - debug( - "Validation of URL %s against allowSaleorUrls param resolves to false, throwing", - saleorApiUrl - ); - - return Response.json( - createRegisterHandlerResponseBody(false, { - code: "SALEOR_URL_PROHIBITED", - message: "This app expects to be installed only in allowed Saleor instances", - }), - { status: 403 } - ); - } - - const { configured: aplConfigured } = await apl.isConfigured(); - - if (!aplConfigured) { - debug("The APL has not been configured"); +export type CreateAppRegisterHandlerOptions = + GenericCreateAppRegisterHandlerOptions; - return Response.json( - createRegisterHandlerResponseBody(false, { - code: "APL_NOT_CONFIGURED", - message: "APL_NOT_CONFIGURED. App is configured properly. Check APL docs for help.", - }), - { - status: 503, - } - ); - } - - // Try to get App ID from the API, to confirm that communication can be established - const appId = await getAppId({ saleorApiUrl, token: authToken }); - if (!appId) { - return Response.json( - createRegisterHandlerResponseBody(false, { - code: "UNKNOWN_APP_ID", - message: `The auth data given during registration request could not be used to fetch app ID. - This usually means that App could not connect to Saleor during installation. Saleor URL that App tried to connect: ${saleorApiUrl}`, - }), - { - status: 401, - } - ); - } - - // Fetch the JWKS which will be used during webhook validation - const jwks = await fetchRemoteJwks(saleorApiUrl); - if (!jwks) { - return Response.json( - createRegisterHandlerResponseBody(false, { - code: "JWKS_NOT_AVAILABLE", - message: "Can't fetch the remote JWKS.", - }), - { - status: 401, - } - ); - } - - const authData = { - domain: saleorDomain, - token: authToken, - saleorApiUrl, - appId, - jwks, - }; - - if (onRequestVerified) { - debug("Calling \"onRequestVerified\" hook"); - - try { - await onRequestVerified(request, { - authData, - respondWithError: createCallbackError, - }); - } catch (e: RegisterCallbackError | unknown) { - debug("\"onRequestVerified\" hook thrown error: %o", e); - - return handleHookError(e); - } - } - - try { - await apl.set(authData); - - if (onAuthAplSaved) { - debug("Calling \"onAuthAplSaved\" hook"); - - try { - await onAuthAplSaved(request, { - authData, - respondWithError: createCallbackError, - }); - } catch (e: RegisterCallbackError | unknown) { - debug("\"onAuthAplSaved\" hook thrown error: %o", e); - - return handleHookError(e); - } - } - } catch (aplError: unknown) { - debug("There was an error during saving the auth data"); - - if (onAplSetFailed) { - debug("Calling \"onAuthAplFailed\" hook"); - - try { - await onAplSetFailed(request, { - authData, - error: aplError, - respondWithError: createCallbackError, - }); - } catch (hookError: RegisterCallbackError | unknown) { - debug("\"onAuthAplFailed\" hook thrown error: %o", hookError); - - return handleHookError(hookError); - } - } - - return Response.json( - createRegisterHandlerResponseBody(false, { - message: "Registration failed: could not save the auth data.", - }), - { status: 500 } - ); - } - - debug("Register complete"); - - return Response.json(createRegisterHandlerResponseBody(true)); +export const createAppRegisterHandler = + (config: CreateAppRegisterHandlerOptions): WebApiHandler => + async (req: Request) => { + const adapter = new WebApiAdapter(req); + const useCase = new ManifestUseCase({ adapter, config }); + const result = await useCase.getResult(); + return adapter.send(result); }; - - return toRequestHandler([ - withMethod("POST"), - withSaleorDomainPresent, - withAuthTokenRequired, - baseHandler, - ]); -}; diff --git a/src/handlers/fetch-api/platform-adapter.ts b/src/handlers/fetch-api/platform-adapter.ts new file mode 100644 index 00000000..814b3ea1 --- /dev/null +++ b/src/handlers/fetch-api/platform-adapter.ts @@ -0,0 +1,47 @@ +import { + HandlerUseCaseResult, + PlatformAdapterInterface, +} from "../shared/generic-adapter-use-case-types"; + +export type WebApiHandlerInput = Request; +export type WebApiHandler = (req: Request) => Response | Promise; + +export class WebApiAdapter implements PlatformAdapterInterface { + constructor(public request: Request) {} + + getHeader(name: string) { + return this.request.headers.get(name); + } + + async getBody() { + const request = this.request.clone(); + try { + return await request.json(); + } catch (err) { + return null; + } + } + + get method() { + return this.request.method as "POST" | "GET"; + } + + send(result: HandlerUseCaseResult): Promise { + let body: string; + + if (result.bodyType === "json") { + body = JSON.stringify(result.body); + } else { + body = result.body; + } + + return Promise.resolve( + new Response(body, { + status: result.status, + headers: { + "Content-Type": result.bodyType === "json" ? "application/json" : "text/plain", + }, + }) + ); + } +} diff --git a/src/handlers/next/create-app-register-handler.ts b/src/handlers/next/create-app-register-handler.ts index edc178ed..c8740ded 100644 --- a/src/handlers/next/create-app-register-handler.ts +++ b/src/handlers/next/create-app-register-handler.ts @@ -1,38 +1,8 @@ -import type { Handler, Request } from "retes"; -import { toNextHandler } from "retes/adapter"; -import { withMethod } from "retes/middleware"; -import { Response } from "retes/response"; +import { NextApiRequest, NextApiResponse } from "next"; -import { SALEOR_API_URL_HEADER, SALEOR_DOMAIN_HEADER } from "../../const"; -import { createDebug } from "../../debug"; -import { fetchRemoteJwks } from "../../fetch-remote-jwks"; -import { getAppId } from "../../get-app-id"; -import { withAuthTokenRequired, withSaleorDomainPresent } from "../../middleware"; import { GenericCreateAppRegisterHandlerOptions } from "../shared/create-app-register-handler-types"; -import { validateAllowSaleorUrls } from "../shared/validate-allow-saleor-urls"; - -const debug = createDebug("createAppRegisterHandler"); - -type HookCallbackErrorParams = { - status?: number; - message?: string; -}; - -class RegisterCallbackError extends Error { - public status = 500; - - constructor(errorParams: HookCallbackErrorParams) { - super(errorParams.message); - - if (errorParams.status) { - this.status = errorParams.status; - } - } -} - -const createCallbackError = (params: HookCallbackErrorParams) => { - throw new RegisterCallbackError(params); -}; +import { ManifestUseCase } from "../shared/manifest-use-case"; +import { NextJsAdapter, NextJsHandlerInput } from "./platform-adapter"; export type RegisterHandlerResponseBody = { success: boolean; @@ -49,197 +19,15 @@ export const createRegisterHandlerResponseBody = ( error, }); -const handleHookError = (e: RegisterCallbackError | unknown) => { - if (e instanceof RegisterCallbackError) { - return new Response( - createRegisterHandlerResponseBody(false, { - code: "REGISTER_HANDLER_HOOK_ERROR", - message: e.message, - }), - { status: e.status } - ); - } - return Response.InternalServerError("Error during app installation"); -}; - // Request type is from retest (Next.js interface) -export type CreateAppRegisterHandlerOptions = GenericCreateAppRegisterHandlerOptions; - -/** - * Creates API handler for Next.js. Creates handler called by Saleor that registers app. - * Hides implementation details if possible - * In the future this will be extracted to separate sdk/next package - */ -export const createAppRegisterHandler = ({ - apl, - allowedSaleorUrls, - onAplSetFailed, - onAuthAplSaved, - onRequestVerified, - onRequestStart, -}: CreateAppRegisterHandlerOptions) => { - const baseHandler: Handler = async (request) => { - debug("Request received"); - - const authToken = request.params.auth_token; - const saleorDomain = request.headers[SALEOR_DOMAIN_HEADER] as string; - const saleorApiUrl = request.headers[SALEOR_API_URL_HEADER] as string; - - if (onRequestStart) { - debug("Calling \"onRequestStart\" hook"); - - try { - await onRequestStart(request, { - authToken, - saleorApiUrl, - saleorDomain, - respondWithError: createCallbackError, - }); - } catch (e: RegisterCallbackError | unknown) { - debug("\"onRequestStart\" hook thrown error: %o", e); - - return handleHookError(e); - } - } - - if (!saleorApiUrl) { - debug("saleorApiUrl doesn't exist in headers"); - } - - if (!validateAllowSaleorUrls(saleorApiUrl, allowedSaleorUrls)) { - debug( - "Validation of URL %s against allowSaleorUrls param resolves to false, throwing", - saleorApiUrl - ); - - return Response.Forbidden( - createRegisterHandlerResponseBody(false, { - code: "SALEOR_URL_PROHIBITED", - message: "This app expects to be installed only in allowed Saleor instances", - }) - ); - } - - const { configured: aplConfigured } = await apl.isConfigured(); - - if (!aplConfigured) { - debug("The APL has not been configured"); - - return new Response( - createRegisterHandlerResponseBody(false, { - code: "APL_NOT_CONFIGURED", - message: "APL_NOT_CONFIGURED. App is configured properly. Check APL docs for help.", - }), - { - status: 503, - } - ); - } - - // Try to get App ID from the API, to confirm that communication can be established - const appId = await getAppId({ saleorApiUrl, token: authToken }); - if (!appId) { - return new Response( - createRegisterHandlerResponseBody(false, { - code: "UNKNOWN_APP_ID", - message: `The auth data given during registration request could not be used to fetch app ID. - This usually means that App could not connect to Saleor during installation. Saleor URL that App tried to connect: ${saleorApiUrl}`, - }), - { - status: 401, - } - ); - } - - // Fetch the JWKS which will be used during webhook validation - const jwks = await fetchRemoteJwks(saleorApiUrl); - if (!jwks) { - return new Response( - createRegisterHandlerResponseBody(false, { - code: "JWKS_NOT_AVAILABLE", - message: "Can't fetch the remote JWKS.", - }), - { - status: 401, - } - ); - } - - const authData = { - domain: saleorDomain, - token: authToken, - saleorApiUrl, - appId, - jwks, - }; - - if (onRequestVerified) { - debug("Calling \"onRequestVerified\" hook"); - - try { - await onRequestVerified(request, { - authData, - respondWithError: createCallbackError, - }); - } catch (e: RegisterCallbackError | unknown) { - debug("\"onRequestVerified\" hook thrown error: %o", e); - - return handleHookError(e); - } - } - - try { - await apl.set(authData); - - if (onAuthAplSaved) { - debug("Calling \"onAuthAplSaved\" hook"); - - try { - await onAuthAplSaved(request, { - authData, - respondWithError: createCallbackError, - }); - } catch (e: RegisterCallbackError | unknown) { - debug("\"onAuthAplSaved\" hook thrown error: %o", e); - - return handleHookError(e); - } - } - } catch (aplError: unknown) { - debug("There was an error during saving the auth data"); - - if (onAplSetFailed) { - debug("Calling \"onAuthAplFailed\" hook"); - - try { - await onAplSetFailed(request, { - authData, - error: aplError, - respondWithError: createCallbackError, - }); - } catch (hookError: RegisterCallbackError | unknown) { - debug("\"onAuthAplFailed\" hook thrown error: %o", hookError); - - return handleHookError(hookError); - } - } - - return Response.InternalServerError( - createRegisterHandlerResponseBody(false, { - message: "Registration failed: could not save the auth data.", - }) - ); - } - - debug("Register complete"); - - return Response.OK(createRegisterHandlerResponseBody(true)); +export type CreateAppRegisterHandlerOptions = + GenericCreateAppRegisterHandlerOptions; + +export const createAppRegisterHandler = + (config: CreateAppRegisterHandlerOptions) => + async (req: NextApiRequest, res: NextApiResponse) => { + const adapter = new NextJsAdapter(req, res); + const useCase = new ManifestUseCase({ adapter, config }); + const result = await useCase.getResult(); + return adapter.send(result); }; - - return toNextHandler([ - withMethod("POST"), - withSaleorDomainPresent, - withAuthTokenRequired, - baseHandler, - ]); -}; diff --git a/src/handlers/next/platform-adapter.ts b/src/handlers/next/platform-adapter.ts new file mode 100644 index 00000000..cfb8b235 --- /dev/null +++ b/src/handlers/next/platform-adapter.ts @@ -0,0 +1,39 @@ +import { NextApiRequest, NextApiResponse } from "next"; + +import { + HandlerUseCaseResult, + PlatformAdapterInterface, +} from "../shared/generic-adapter-use-case-types"; + +export type NextJsHandlerInput = NextApiRequest; +export type NextJsHandler = ( + req: NextApiRequest, + res: NextApiResponse +) => Promise; + +export class NextJsAdapter implements PlatformAdapterInterface { + readonly type = "next" as const; + + constructor(public request: NextApiRequest, private res: NextApiResponse) {} + + getHeader(name: string) { + const header = this.request.headers[name]; + return Array.isArray(header) ? header.join(", ") : header ?? null; + } + + getBody(): Promise { + return Promise.resolve(this.request.body); + } + + get method() { + return this.request.method as "POST" | "GET"; + } + + async send(result: HandlerUseCaseResult): Promise { + if (result.bodyType === "json") { + this.res.status(result.status).json(result.body); + } else { + this.res.status(result.status).send(result.body); + } + } +} diff --git a/src/handlers/shared/generic-adapter-use-case-types.ts b/src/handlers/shared/generic-adapter-use-case-types.ts new file mode 100644 index 00000000..400866f3 --- /dev/null +++ b/src/handlers/shared/generic-adapter-use-case-types.ts @@ -0,0 +1,40 @@ +import { WebApiHandlerInput } from "../fetch-api/platform-adapter"; +import { NextJsHandlerInput } from "../next/platform-adapter"; + +/** Status code of the result, for most platforms it's mapped to HTTP status code + * however when request is not HTTP it can be mapped to something else */ +export type ResultStatusCodes = 200 | 201 | 400 | 401 | 403 | 404 | 500 | 503; + +/** Shape of result that should be returned from use case + * that is then translated by adapter to a valid platform response */ +export type HandlerUseCaseResult = + | { + status: ResultStatusCodes; + body: Body; + bodyType: "json"; + } + | { + status: ResultStatusCodes; + body: string; + bodyType: "string"; + }; + +/** + * Interface for adapters that translate specific platform objects (e.g. Web API, Next.js) + * into a common interface that can be used in each handler use case + * */ +export interface PlatformAdapterInterface { + send(result: HandlerUseCaseResult): unknown; + getHeader(name: string): string | null; + getBody(): Promise; + method: "POST" | "GET"; + request: T; +} + +/** Interfaces for use case handlers that encapsulate business logic + * (e.g. validating headers, checking HTTP method, etc. ) */ +export interface HandlerUseCaseInterface { + getResult(): Promise; +} + +export type HandlerInput = NextJsHandlerInput | WebApiHandlerInput; diff --git a/src/handlers/shared/manifest-use-case.ts b/src/handlers/shared/manifest-use-case.ts new file mode 100644 index 00000000..a1d106dd --- /dev/null +++ b/src/handlers/shared/manifest-use-case.ts @@ -0,0 +1,318 @@ +/* eslint-disable max-classes-per-file */ +import { AuthData } from "../../APL"; +import { SALEOR_API_URL_HEADER, SALEOR_DOMAIN_HEADER } from "../../const"; +import { createDebug } from "../../debug"; +import { fetchRemoteJwks } from "../../fetch-remote-jwks"; +import { getAppId } from "../../get-app-id"; +import { HasAPL } from "../../saleor-app"; +import { + HandlerInput, + HandlerUseCaseInterface, + HandlerUseCaseResult, + PlatformAdapterInterface, + ResultStatusCodes, +} from "./generic-adapter-use-case-types"; +import { validateAllowSaleorUrls } from "./validate-allow-saleor-urls"; + +const debug = createDebug("createAppRegisterHandler"); + +// TODO: Make this private methods? +// Copy pasted from existing manifest handler +class RegisterCallbackError extends Error { + public status = 500; + + constructor(errorParams: HookCallbackErrorParams) { + super(errorParams.message); + + if (errorParams.status) { + this.status = errorParams.status; + } + } +} + +export type RegisterHandlerResponseBody = { + success: boolean; + error?: { + code?: string; + message?: string; + }; +}; + +export const createRegisterHandlerResponseBody = ( + success: boolean, + error?: RegisterHandlerResponseBody["error"], + statusCode?: ResultStatusCodes +): HandlerUseCaseResult => ({ + status: statusCode ?? success ? 200 : 500, + body: { + success, + error, + }, + bodyType: "json", +}); + +const handleHookError = (e: RegisterCallbackError | unknown): HandlerUseCaseResult => { + if (e instanceof RegisterCallbackError) { + return createRegisterHandlerResponseBody(false, { + code: "REGISTER_HANDLER_HOOK_ERROR", + message: e.message, + }); + } + return { + status: 500, + body: "Error during app installation", + bodyType: "string", + }; +}; + +const createCallbackError: CallbackErrorHandler = (params: HookCallbackErrorParams) => { + throw new RegisterCallbackError(params); +}; + +export type HookCallbackErrorParams = { + status?: number; + message?: string; +}; + +export type CallbackErrorHandler = (params: HookCallbackErrorParams) => never; + +export type GenericCreateAppRegisterHandlerOptions = HasAPL & { + /** + * Protect app from being registered in Saleor other than specific. + * By default, allow everything. + * + * Provide array of either a full Saleor API URL (eg. my-shop.saleor.cloud/graphql/) + * or a function that receives a full Saleor API URL ad returns true/false. + */ + allowedSaleorUrls?: Array boolean)>; + /** + * Run right after Saleor calls this endpoint + */ + onRequestStart?( + request: Request, + context: { + authToken?: string; + saleorDomain?: string; + saleorApiUrl?: string; + respondWithError: CallbackErrorHandler; + } + ): Promise; + /** + * Run after all security checks + */ + onRequestVerified?( + request: Request, + context: { + authData: AuthData; + respondWithError: CallbackErrorHandler; + } + ): Promise; + /** + * Run after APL successfully AuthData, assuming that APL.set will reject a Promise in case of error + */ + onAuthAplSaved?( + request: Request, + context: { + authData: AuthData; + respondWithError: CallbackErrorHandler; + } + ): Promise; + /** + * Run after APL fails to set AuthData + */ + onAplSetFailed?( + request: Request, + context: { + authData: AuthData; + error: unknown; + respondWithError: CallbackErrorHandler; + } + ): Promise; +}; + +export class ManifestUseCase implements HandlerUseCaseInterface { + private adapter: PlatformAdapterInterface; + + public config: GenericCreateAppRegisterHandlerOptions; + + constructor({ + adapter, + config, + }: { + adapter: PlatformAdapterInterface; + config: GenericCreateAppRegisterHandlerOptions; + }) { + this.adapter = adapter; + this.config = config; + } + + /** TODO: Add missing retes methods: + * withMethod("POST"), + * withSaleorDomainPresent, + * withAuthTokenRequired, + * baseHandler, + * */ + async getResult(): Promise { + debug("Request received"); + + const saleorDomain = this.adapter.getHeader(SALEOR_DOMAIN_HEADER) as string; + const saleorApiUrl = this.adapter.getHeader(SALEOR_API_URL_HEADER) as string; + + let body: { auth_token: string }; + try { + body = (await this.adapter.getBody()) as { auth_token: string }; + } catch (err) { + // TODO: Handle error + throw new Error("Cannot parse body"); + } + + const authToken = body.auth_token; + + if (this.config.onRequestStart) { + debug("Calling \"onRequestStart\" hook"); + + try { + await this.config.onRequestStart(this.adapter.request, { + authToken, + saleorApiUrl, + saleorDomain, + respondWithError: createCallbackError, + }); + } catch (e: RegisterCallbackError | unknown) { + debug("\"onRequestStart\" hook thrown error: %o", e); + + return handleHookError(e); + } + } + + if (!saleorApiUrl) { + debug("saleorApiUrl doesn't exist in headers"); + } + + if (!validateAllowSaleorUrls(saleorApiUrl, this.config.allowedSaleorUrls)) { + debug( + "Validation of URL %s against allowSaleorUrls param resolves to false, throwing", + saleorApiUrl + ); + + return createRegisterHandlerResponseBody( + false, + { + code: "SALEOR_URL_PROHIBITED", + message: "This app expects to be installed only in allowed Saleor instances", + }, + 403 + ); + } + + const { configured: aplConfigured } = await this.config.apl.isConfigured(); + + if (!aplConfigured) { + debug("The APL has not been configured"); + + return createRegisterHandlerResponseBody( + false, + { + code: "APL_NOT_CONFIGURED", + message: "APL_NOT_CONFIGURED. App is configured properly. Check APL docs for help.", + }, + 503 + ); + } + + // Try to get App ID from the API, to confirm that communication can be established + const appId = await getAppId({ saleorApiUrl, token: authToken }); + if (!appId) { + return createRegisterHandlerResponseBody( + false, + { + code: "UNKNOWN_APP_ID", + message: `The auth data given during registration request could not be used to fetch app ID. + This usually means that App could not connect to Saleor during installation. Saleor URL that App tried to connect: ${saleorApiUrl}`, + }, + 401 + ); + } + + // Fetch the JWKS which will be used during webhook validation + const jwks = await fetchRemoteJwks(saleorApiUrl); + if (!jwks) { + return createRegisterHandlerResponseBody( + false, + { + code: "JWKS_NOT_AVAILABLE", + message: "Can't fetch the remote JWKS.", + }, + 401 + ); + } + + const authData = { + domain: saleorDomain, + token: authToken, + saleorApiUrl, + appId, + jwks, + }; + + if (this.config.onRequestVerified) { + debug("Calling \"onRequestVerified\" hook"); + + try { + await this.config.onRequestVerified(this.adapter.request, { + authData, + respondWithError: createCallbackError, + }); + } catch (e: RegisterCallbackError | unknown) { + debug("\"onRequestVerified\" hook thrown error: %o", e); + + return handleHookError(e); + } + } + + try { + await this.config.apl.set(authData); + + if (this.config.onAuthAplSaved) { + debug("Calling \"onAuthAplSaved\" hook"); + + try { + await this.config.onAuthAplSaved(this.adapter.request, { + authData, + respondWithError: createCallbackError, + }); + } catch (e: RegisterCallbackError | unknown) { + debug("\"onAuthAplSaved\" hook thrown error: %o", e); + + return handleHookError(e); + } + } + } catch (aplError: unknown) { + debug("There was an error during saving the auth data"); + + if (this.config.onAplSetFailed) { + debug("Calling \"onAuthAplFailed\" hook"); + + try { + await this.config.onAplSetFailed(this.adapter.request, { + authData, + error: aplError, + respondWithError: createCallbackError, + }); + } catch (hookError: RegisterCallbackError | unknown) { + debug("\"onAuthAplFailed\" hook thrown error: %o", hookError); + + return handleHookError(hookError); + } + } + + return createRegisterHandlerResponseBody(false, { + message: "Registration failed: could not save the auth data.", + }); + } + + debug("Register complete"); + + return createRegisterHandlerResponseBody(true); + } +} From 69203aa594263420f16fc4c7dac26932b383c065 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Wed, 15 Jan 2025 13:24:32 +0100 Subject: [PATCH 22/58] Add AWS lambda adapter --- package.json | 7 + pnpm-lock.yaml | 342 ++++++++++++++++++ .../aws-lambda/create-app-register.ts | 33 ++ src/handlers/aws-lambda/platform-adapter.ts | 48 +++ src/handlers/fetch-api/platform-adapter.ts | 26 +- .../shared/generic-adapter-use-case-types.ts | 5 +- 6 files changed, 442 insertions(+), 19 deletions(-) create mode 100644 src/handlers/aws-lambda/create-app-register.ts create mode 100644 src/handlers/aws-lambda/platform-adapter.ts diff --git a/package.json b/package.json index 2afa2030..7375a874 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,9 @@ "author": "", "license": "ISC", "peerDependencies": { + "@types/aws-lambda": "8.10.147", "@vercel/kv": "^1.0.0", + "aws-lambda": "1.0.7", "graphql": ">=16.6.0", "next": ">=12", "react": ">=17", @@ -40,6 +42,7 @@ "@changesets/cli": "2.27.1", "@testing-library/dom": "^8.17.1", "@testing-library/react": "^13.4.0", + "@types/aws-lambda": "8.10.147", "@types/debug": "^4.1.7", "@types/node": "^18.7.15", "@types/react": "18.0.21", @@ -50,6 +53,7 @@ "@vercel/kv": "1.0.0", "@vitejs/plugin-react": "^3.0.1", "@vitest/coverage-c8": "^0.27.2", + "aws-lambda": "1.0.7", "clean-publish": "^4.0.1", "eslint": "8.23.0", "eslint-config-airbnb": "^19.0.4", @@ -80,6 +84,9 @@ "peerDependenciesMeta": { "@vercel/kv": { "optional": true + }, + "aws-lambda": { + "optional": true } }, "lint-staged": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9099d60e..4800cce4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -37,6 +37,9 @@ devDependencies: '@testing-library/react': specifier: ^13.4.0 version: 13.4.0(react-dom@18.2.0)(react@18.2.0) + '@types/aws-lambda': + specifier: 8.10.147 + version: 8.10.147 '@types/debug': specifier: ^4.1.7 version: 4.1.7 @@ -67,6 +70,9 @@ devDependencies: '@vitest/coverage-c8': specifier: ^0.27.2 version: 0.27.2(jsdom@20.0.3) + aws-lambda: + specifier: 1.0.7 + version: 1.0.7 clean-publish: specifier: ^4.0.1 version: 4.0.1 @@ -1121,6 +1127,10 @@ packages: resolution: {integrity: sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==} dev: true + /@types/aws-lambda@8.10.147: + resolution: {integrity: sha512-nD0Z9fNIZcxYX5Mai2CTmFD7wX7UldCkW2ezCF8D1T5hdiLsnTWDGRpfRYntU6VjTdLQjOvyszru7I1c1oCQew==} + dev: true + /@types/chai-subset@1.3.3: resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==} dependencies: @@ -1653,6 +1663,40 @@ packages: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} dev: true + /available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + dependencies: + possible-typed-array-names: 1.0.0 + dev: true + + /aws-lambda@1.0.7: + resolution: {integrity: sha512-9GNFMRrEMG5y3Jvv+V4azWvc+qNWdWLTjDdhf/zgMlz8haaaLWv0xeAIWxz9PuWUBawsVxy0zZotjCdR3Xq+2w==} + hasBin: true + dependencies: + aws-sdk: 2.1692.0 + commander: 3.0.2 + js-yaml: 3.14.1 + watchpack: 2.4.2 + dev: true + + /aws-sdk@2.1692.0: + resolution: {integrity: sha512-x511uiJ/57FIsbgUe5csJ13k3uzu25uWQE+XqfBis/sB0SFoiElJWXRkgEAUh0U6n40eT3ay5Ue4oPkRMu1LYw==} + engines: {node: '>= 10.0.0'} + requiresBuild: true + dependencies: + buffer: 4.9.2 + events: 1.1.1 + ieee754: 1.1.13 + jmespath: 0.16.0 + querystring: 0.2.0 + sax: 1.2.1 + url: 0.10.3 + util: 0.12.5 + uuid: 8.0.0 + xml2js: 0.6.2 + dev: true + /axe-core@4.4.3: resolution: {integrity: sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==} engines: {node: '>=4'} @@ -1666,6 +1710,10 @@ packages: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: true + /better-path-resolve@1.0.0: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} @@ -1719,6 +1767,14 @@ packages: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} dev: true + /buffer@4.9.2: + resolution: {integrity: sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.1.13 + isarray: 1.0.0 + dev: true + /bundle-require@3.1.0(esbuild@0.15.7): resolution: {integrity: sha512-IIXtAO7fKcwPHNPt9kY/WNVJqy7NDy6YqJvv6ENH0TOZoJ+yjpEsn1w40WKZbR2ibfu5g1rfgJTvmFHpm5aOMA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -1765,6 +1821,14 @@ packages: engines: {node: '>=8'} dev: true + /call-bind-apply-helpers@1.0.1: + resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + dev: true + /call-bind@1.0.2: resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} dependencies: @@ -1772,6 +1836,24 @@ packages: get-intrinsic: 1.1.2 dev: true + /call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + dependencies: + call-bind-apply-helpers: 1.0.1 + es-define-property: 1.0.1 + get-intrinsic: 1.2.7 + set-function-length: 1.2.2 + dev: true + + /call-bound@1.0.3: + resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind-apply-helpers: 1.0.1 + get-intrinsic: 1.2.7 + dev: true + /callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -1954,6 +2036,10 @@ packages: delayed-stream: 1.0.0 dev: true + /commander@3.0.2: + resolution: {integrity: sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==} + dev: true + /commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} @@ -2137,6 +2223,15 @@ packages: clone: 1.0.4 dev: true + /define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + dev: true + /define-lazy-prop@2.0.0: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} engines: {node: '>=8'} @@ -2207,6 +2302,15 @@ packages: webidl-conversions: 7.0.0 dev: true + /dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + dependencies: + call-bind-apply-helpers: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + dev: true + /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} dev: true @@ -2278,6 +2382,23 @@ packages: unbox-primitive: 1.0.2 dev: true + /es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + dev: true + + /es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + dev: true + + /es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + dev: true + /es-shim-unscopables@1.0.0: resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} dependencies: @@ -3113,6 +3234,11 @@ packages: engines: {node: '>=0.10.0'} dev: true + /events@1.1.1: + resolution: {integrity: sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==} + engines: {node: '>=0.4.x'} + dev: true + /execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -3239,6 +3365,12 @@ packages: resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} dev: true + /for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + dependencies: + is-callable: 1.2.4 + dev: true + /foreground-child@2.0.0: resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==} engines: {node: '>=8.0.0'} @@ -3295,6 +3427,10 @@ packages: resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} dev: true + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: true + /function.prototype.name@1.1.5: resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} engines: {node: '>= 0.4'} @@ -3335,6 +3471,30 @@ packages: has-symbols: 1.0.3 dev: true + /get-intrinsic@1.2.7: + resolution: {integrity: sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind-apply-helpers: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + dev: true + + /get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + dev: true + /get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} @@ -3366,6 +3526,10 @@ packages: is-glob: 4.0.3 dev: true + /glob-to-regexp@0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + dev: true + /glob@7.1.6: resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} dependencies: @@ -3431,6 +3595,11 @@ packages: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} dev: true + /gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + dev: true + /graceful-fs@4.2.10: resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} dev: true @@ -3469,11 +3638,22 @@ packages: get-intrinsic: 1.1.2 dev: true + /has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + dependencies: + es-define-property: 1.0.1 + dev: true + /has-symbols@1.0.3: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} dev: true + /has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + dev: true + /has-tostringtag@1.0.0: resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} engines: {node: '>= 0.4'} @@ -3481,6 +3661,13 @@ packages: has-symbols: 1.0.3 dev: true + /has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: true + /has@1.0.3: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} engines: {node: '>= 0.4.0'} @@ -3488,6 +3675,13 @@ packages: function-bind: 1.1.1 dev: true + /hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + dev: true + /hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} dev: true @@ -3568,6 +3762,10 @@ packages: safer-buffer: 2.1.2 dev: true + /ieee754@1.1.13: + resolution: {integrity: sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==} + dev: true + /ignore@5.2.0: resolution: {integrity: sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==} engines: {node: '>= 4'} @@ -3610,6 +3808,14 @@ packages: side-channel: 1.0.4 dev: true + /is-arguments@1.2.0: + resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + dev: true + /is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} dev: true @@ -3674,6 +3880,16 @@ packages: engines: {node: '>=12'} dev: true + /is-generator-function@1.1.0: + resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.3 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + dev: true + /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -3715,6 +3931,16 @@ packages: has-tostringtag: 1.0.0 dev: true + /is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.3 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + dev: true + /is-shared-array-buffer@1.0.2: resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} dependencies: @@ -3752,6 +3978,13 @@ packages: has-symbols: 1.0.3 dev: true + /is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + dependencies: + which-typed-array: 1.1.18 + dev: true + /is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: @@ -3770,6 +4003,10 @@ packages: is-docker: 2.2.1 dev: true + /isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + dev: true + /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: true @@ -3796,6 +4033,11 @@ packages: istanbul-lib-report: 3.0.0 dev: true + /jmespath@0.16.0: + resolution: {integrity: sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==} + engines: {node: '>= 0.6.0'} + dev: true + /jose@4.14.4: resolution: {integrity: sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==} dev: false @@ -4130,6 +4372,11 @@ packages: engines: {node: '>=8'} dev: true + /math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + dev: true + /media-typer@0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} @@ -4674,6 +4921,11 @@ packages: pathe: 1.1.0 dev: true + /possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + dev: true + /postcss-load-config@3.1.4: resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} engines: {node: '>= 10'} @@ -4759,6 +5011,10 @@ packages: resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} dev: true + /punycode@1.3.2: + resolution: {integrity: sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==} + dev: true + /punycode@2.1.1: resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} engines: {node: '>=6'} @@ -4774,6 +5030,12 @@ packages: strict-uri-encode: 2.0.0 dev: true + /querystring@0.2.0: + resolution: {integrity: sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==} + engines: {node: '>=0.4.x'} + deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead. + dev: true + /querystringify@2.2.0: resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} dev: true @@ -5006,9 +5268,22 @@ packages: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} dev: true + /safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-regex: 1.2.1 + dev: true + /safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + /sax@1.2.1: + resolution: {integrity: sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==} + dev: true + /saxes@6.0.0: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} @@ -5052,6 +5327,18 @@ packages: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} dev: true + /set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.7 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + dev: true + /setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} dev: false @@ -5723,6 +6010,13 @@ packages: requires-port: 1.0.0 dev: true + /url@0.10.3: + resolution: {integrity: sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==} + dependencies: + punycode: 1.3.2 + querystring: 0.2.0 + dev: true + /use-sync-external-store@1.2.0(react@18.2.0): resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} peerDependencies: @@ -5731,6 +6025,21 @@ packages: react: 18.2.0 dev: true + /util@0.12.5: + resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} + dependencies: + inherits: 2.0.4 + is-arguments: 1.2.0 + is-generator-function: 1.1.0 + is-typed-array: 1.1.15 + which-typed-array: 1.1.18 + dev: true + + /uuid@8.0.0: + resolution: {integrity: sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==} + hasBin: true + dev: true + /uuid@9.0.0: resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==} hasBin: true @@ -5952,6 +6261,14 @@ packages: xml-name-validator: 4.0.0 dev: true + /watchpack@2.4.2: + resolution: {integrity: sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==} + engines: {node: '>=10.13.0'} + dependencies: + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.10 + dev: true + /wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} dependencies: @@ -6017,6 +6334,18 @@ packages: path-exists: 4.0.0 dev: true + /which-typed-array@1.1.18: + resolution: {integrity: sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.3 + for-each: 0.3.3 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + dev: true + /which@1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} hasBin: true @@ -6086,6 +6415,19 @@ packages: engines: {node: '>=12'} dev: true + /xml2js@0.6.2: + resolution: {integrity: sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==} + engines: {node: '>=4.0.0'} + dependencies: + sax: 1.2.1 + xmlbuilder: 11.0.1 + dev: true + + /xmlbuilder@11.0.1: + resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} + engines: {node: '>=4.0'} + dev: true + /xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} dev: true diff --git a/src/handlers/aws-lambda/create-app-register.ts b/src/handlers/aws-lambda/create-app-register.ts new file mode 100644 index 00000000..11cfc3ce --- /dev/null +++ b/src/handlers/aws-lambda/create-app-register.ts @@ -0,0 +1,33 @@ +import { APIGatewayProxyEventV2, Context } from "aws-lambda"; + +import { GenericCreateAppRegisterHandlerOptions } from "../shared/create-app-register-handler-types"; +import { ManifestUseCase } from "../shared/manifest-use-case"; +import { AwsLambdaAdapter, AWSLambdaHandler, WebApiHandlerInput } from "./platform-adapter"; + +export type RegisterHandlerResponseBody = { + success: boolean; + error?: { + code?: string; + message?: string; + }; +}; + +export const createRegisterHandlerResponseBody = ( + success: boolean, + error?: RegisterHandlerResponseBody["error"] +): RegisterHandlerResponseBody => ({ + success, + error, +}); + +export type CreateAppRegisterHandlerOptions = + GenericCreateAppRegisterHandlerOptions; + +export const createAppRegisterHandler = + (config: CreateAppRegisterHandlerOptions): AWSLambdaHandler => + async (event: APIGatewayProxyEventV2, context: Context) => { + const adapter = new AwsLambdaAdapter(event, context); + const useCase = new ManifestUseCase({ adapter, config }); + const result = await useCase.getResult(); + return adapter.send(result); + }; diff --git a/src/handlers/aws-lambda/platform-adapter.ts b/src/handlers/aws-lambda/platform-adapter.ts new file mode 100644 index 00000000..f1385043 --- /dev/null +++ b/src/handlers/aws-lambda/platform-adapter.ts @@ -0,0 +1,48 @@ +import type { APIGatewayProxyEventV2, APIGatewayProxyResultV2, Context } from "aws-lambda"; + +import { + HandlerUseCaseResult, + PlatformAdapterInterface, +} from "../shared/generic-adapter-use-case-types"; + +export type AwsLambdaHandlerInput = APIGatewayProxyEventV2; +export type AWSLambdaHandler = ( + event: APIGatewayProxyEventV2, + context: Context +) => Promise; + +export class AwsLambdaAdapter implements PlatformAdapterInterface { + public request: AwsLambdaHandlerInput; + + constructor(private event: APIGatewayProxyEventV2, private context: Context) { + this.request = event; + } + + getHeader(name: string): string | null { + return this.request.headers[name] || null; + } + + async getBody(): Promise { + try { + return JSON.parse(this.request.body || "{}"); + } catch (err) { + return null; + } + } + + get method(): string { + return this.event.requestContext.http.method; + } + + async send(result: HandlerUseCaseResult): Promise { + const body = result.bodyType === "json" ? JSON.stringify(result.body) : result.body; + + return { + statusCode: result.status, + headers: { + "Content-Type": result.bodyType === "json" ? "application/json" : "text/plain", + }, + body, + }; + } +} diff --git a/src/handlers/fetch-api/platform-adapter.ts b/src/handlers/fetch-api/platform-adapter.ts index 814b3ea1..1e00c0c0 100644 --- a/src/handlers/fetch-api/platform-adapter.ts +++ b/src/handlers/fetch-api/platform-adapter.ts @@ -26,22 +26,14 @@ export class WebApiAdapter implements PlatformAdapterInterface { - let body: string; - - if (result.bodyType === "json") { - body = JSON.stringify(result.body); - } else { - body = result.body; - } - - return Promise.resolve( - new Response(body, { - status: result.status, - headers: { - "Content-Type": result.bodyType === "json" ? "application/json" : "text/plain", - }, - }) - ); + async send(result: HandlerUseCaseResult): Promise { + const body = result.bodyType === "json" ? JSON.stringify(result.body) : result.body; + + return new Response(body, { + status: result.status, + headers: { + "Content-Type": result.bodyType === "json" ? "application/json" : "text/plain", + }, + }); } } diff --git a/src/handlers/shared/generic-adapter-use-case-types.ts b/src/handlers/shared/generic-adapter-use-case-types.ts index 400866f3..ae8b5dab 100644 --- a/src/handlers/shared/generic-adapter-use-case-types.ts +++ b/src/handlers/shared/generic-adapter-use-case-types.ts @@ -1,3 +1,4 @@ +import { AwsLambdaHandlerInput } from "../aws-lambda/platform-adapter"; import { WebApiHandlerInput } from "../fetch-api/platform-adapter"; import { NextJsHandlerInput } from "../next/platform-adapter"; @@ -27,7 +28,7 @@ export interface PlatformAdapterInterface { send(result: HandlerUseCaseResult): unknown; getHeader(name: string): string | null; getBody(): Promise; - method: "POST" | "GET"; + method: string; request: T; } @@ -37,4 +38,4 @@ export interface HandlerUseCaseInterface { getResult(): Promise; } -export type HandlerInput = NextJsHandlerInput | WebApiHandlerInput; +export type HandlerInput = NextJsHandlerInput | WebApiHandlerInput | AwsLambdaHandlerInput; From bb36e9785b376018ef537be1529c82527bc9ad66 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Wed, 15 Jan 2025 13:28:57 +0100 Subject: [PATCH 23/58] Update exports --- src/handlers/aws-lambda/create-app-register.ts | 14 +++----------- .../fetch-api/create-app-register-handler.ts | 10 +--------- src/handlers/next/create-app-register-handler.ts | 13 +++++-------- 3 files changed, 9 insertions(+), 28 deletions(-) diff --git a/src/handlers/aws-lambda/create-app-register.ts b/src/handlers/aws-lambda/create-app-register.ts index 11cfc3ce..71fbe589 100644 --- a/src/handlers/aws-lambda/create-app-register.ts +++ b/src/handlers/aws-lambda/create-app-register.ts @@ -1,16 +1,8 @@ import { APIGatewayProxyEventV2, Context } from "aws-lambda"; import { GenericCreateAppRegisterHandlerOptions } from "../shared/create-app-register-handler-types"; -import { ManifestUseCase } from "../shared/manifest-use-case"; -import { AwsLambdaAdapter, AWSLambdaHandler, WebApiHandlerInput } from "./platform-adapter"; - -export type RegisterHandlerResponseBody = { - success: boolean; - error?: { - code?: string; - message?: string; - }; -}; +import { ManifestUseCase, RegisterHandlerResponseBody } from "../shared/manifest-use-case"; +import { AwsLambdaAdapter, AWSLambdaHandler, AwsLambdaHandlerInput } from "./platform-adapter"; export const createRegisterHandlerResponseBody = ( success: boolean, @@ -21,7 +13,7 @@ export const createRegisterHandlerResponseBody = ( }); export type CreateAppRegisterHandlerOptions = - GenericCreateAppRegisterHandlerOptions; + GenericCreateAppRegisterHandlerOptions; export const createAppRegisterHandler = (config: CreateAppRegisterHandlerOptions): AWSLambdaHandler => diff --git a/src/handlers/fetch-api/create-app-register-handler.ts b/src/handlers/fetch-api/create-app-register-handler.ts index 5af52134..65fddf59 100644 --- a/src/handlers/fetch-api/create-app-register-handler.ts +++ b/src/handlers/fetch-api/create-app-register-handler.ts @@ -1,15 +1,7 @@ import { GenericCreateAppRegisterHandlerOptions } from "../shared/create-app-register-handler-types"; -import { ManifestUseCase } from "../shared/manifest-use-case"; +import { ManifestUseCase, RegisterHandlerResponseBody } from "../shared/manifest-use-case"; import { WebApiAdapter, WebApiHandler, WebApiHandlerInput } from "./platform-adapter"; -export type RegisterHandlerResponseBody = { - success: boolean; - error?: { - code?: string; - message?: string; - }; -}; - export const createRegisterHandlerResponseBody = ( success: boolean, error?: RegisterHandlerResponseBody["error"] diff --git a/src/handlers/next/create-app-register-handler.ts b/src/handlers/next/create-app-register-handler.ts index c8740ded..d321de79 100644 --- a/src/handlers/next/create-app-register-handler.ts +++ b/src/handlers/next/create-app-register-handler.ts @@ -1,16 +1,13 @@ import { NextApiRequest, NextApiResponse } from "next"; import { GenericCreateAppRegisterHandlerOptions } from "../shared/create-app-register-handler-types"; -import { ManifestUseCase } from "../shared/manifest-use-case"; +import { ManifestUseCase, RegisterHandlerResponseBody } from "../shared/manifest-use-case"; import { NextJsAdapter, NextJsHandlerInput } from "./platform-adapter"; -export type RegisterHandlerResponseBody = { - success: boolean; - error?: { - code?: string; - message?: string; - }; -}; +// Re-export types for backwards compatibility + +export type { RegisterHandlerResponseBody }; + export const createRegisterHandlerResponseBody = ( success: boolean, error?: RegisterHandlerResponseBody["error"] From 631ede1149327f04249d3be542ce105990532775 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Wed, 15 Jan 2025 13:52:20 +0100 Subject: [PATCH 24/58] Fix wrong use-case name --- .../aws-lambda/create-app-register.ts | 4 +- .../fetch-api/create-app-register-handler.ts | 4 +- .../next/create-app-register-handler.ts | 4 +- src/handlers/shared/adapter-middleware.ts | 68 +++++++++++++++++++ .../shared/generic-adapter-use-case-types.ts | 17 ++++- ...ifest-use-case.ts => register-use-case.ts} | 36 +++++++++- 6 files changed, 123 insertions(+), 10 deletions(-) create mode 100644 src/handlers/shared/adapter-middleware.ts rename src/handlers/shared/{manifest-use-case.ts => register-use-case.ts} (90%) diff --git a/src/handlers/aws-lambda/create-app-register.ts b/src/handlers/aws-lambda/create-app-register.ts index 71fbe589..dbb5de0e 100644 --- a/src/handlers/aws-lambda/create-app-register.ts +++ b/src/handlers/aws-lambda/create-app-register.ts @@ -1,7 +1,7 @@ import { APIGatewayProxyEventV2, Context } from "aws-lambda"; import { GenericCreateAppRegisterHandlerOptions } from "../shared/create-app-register-handler-types"; -import { ManifestUseCase, RegisterHandlerResponseBody } from "../shared/manifest-use-case"; +import { RegisterHandlerResponseBody, RegisterUseCase } from "../shared/register-use-case"; import { AwsLambdaAdapter, AWSLambdaHandler, AwsLambdaHandlerInput } from "./platform-adapter"; export const createRegisterHandlerResponseBody = ( @@ -19,7 +19,7 @@ export const createAppRegisterHandler = (config: CreateAppRegisterHandlerOptions): AWSLambdaHandler => async (event: APIGatewayProxyEventV2, context: Context) => { const adapter = new AwsLambdaAdapter(event, context); - const useCase = new ManifestUseCase({ adapter, config }); + const useCase = new RegisterUseCase({ adapter, config }); const result = await useCase.getResult(); return adapter.send(result); }; diff --git a/src/handlers/fetch-api/create-app-register-handler.ts b/src/handlers/fetch-api/create-app-register-handler.ts index 65fddf59..80aa1c4e 100644 --- a/src/handlers/fetch-api/create-app-register-handler.ts +++ b/src/handlers/fetch-api/create-app-register-handler.ts @@ -1,5 +1,5 @@ import { GenericCreateAppRegisterHandlerOptions } from "../shared/create-app-register-handler-types"; -import { ManifestUseCase, RegisterHandlerResponseBody } from "../shared/manifest-use-case"; +import { RegisterHandlerResponseBody, RegisterUseCase } from "../shared/register-use-case"; import { WebApiAdapter, WebApiHandler, WebApiHandlerInput } from "./platform-adapter"; export const createRegisterHandlerResponseBody = ( @@ -17,7 +17,7 @@ export const createAppRegisterHandler = (config: CreateAppRegisterHandlerOptions): WebApiHandler => async (req: Request) => { const adapter = new WebApiAdapter(req); - const useCase = new ManifestUseCase({ adapter, config }); + const useCase = new RegisterUseCase({ adapter, config }); const result = await useCase.getResult(); return adapter.send(result); }; diff --git a/src/handlers/next/create-app-register-handler.ts b/src/handlers/next/create-app-register-handler.ts index d321de79..3b76134f 100644 --- a/src/handlers/next/create-app-register-handler.ts +++ b/src/handlers/next/create-app-register-handler.ts @@ -1,7 +1,7 @@ import { NextApiRequest, NextApiResponse } from "next"; import { GenericCreateAppRegisterHandlerOptions } from "../shared/create-app-register-handler-types"; -import { ManifestUseCase, RegisterHandlerResponseBody } from "../shared/manifest-use-case"; +import { RegisterHandlerResponseBody, RegisterUseCase } from "../shared/register-use-case"; import { NextJsAdapter, NextJsHandlerInput } from "./platform-adapter"; // Re-export types for backwards compatibility @@ -24,7 +24,7 @@ export const createAppRegisterHandler = (config: CreateAppRegisterHandlerOptions) => async (req: NextApiRequest, res: NextApiResponse) => { const adapter = new NextJsAdapter(req, res); - const useCase = new ManifestUseCase({ adapter, config }); + const useCase = new RegisterUseCase({ adapter, config }); const result = await useCase.getResult(); return adapter.send(result); }; diff --git a/src/handlers/shared/adapter-middleware.ts b/src/handlers/shared/adapter-middleware.ts new file mode 100644 index 00000000..e22c1ec6 --- /dev/null +++ b/src/handlers/shared/adapter-middleware.ts @@ -0,0 +1,68 @@ +import { + SALEOR_API_URL_HEADER, + SALEOR_AUTHORIZATION_BEARER_HEADER, + SALEOR_DOMAIN_HEADER, + SALEOR_EVENT_HEADER, + SALEOR_SCHEMA_VERSION, + SALEOR_SIGNATURE_HEADER, +} from "../../const"; +import { createMiddlewareDebug } from "../../middleware/middleware-debug"; +import { + HandlerUseCaseResult, + HTTPMethod, + PlatformAdapterInterface, +} from "./generic-adapter-use-case-types"; + +const debug = createMiddlewareDebug("PlatformAdapterMiddleware"); + +export class PlatformAdapterMiddleware { + constructor(private adapter: PlatformAdapterInterface) {} + + withMethod(methods: HTTPMethod[]): HandlerUseCaseResult | null { + if (!methods.includes(this.adapter.method)) { + return { + body: "Method not allowed", + bodyType: "string", + status: 405, + }; + } + + return null; + } + + withSaleorDomainPresent(): HandlerUseCaseResult | null { + const { domain } = this.getSaleorHeaders(); + debug("withSaleorDomainPresent middleware called with domain in header: %s", domain); + + if (!domain) { + debug("Domain not found in header, will respond with Bad Request"); + + return { + body: "Missing Saleor domain header.", + bodyType: "string", + status: 400, + }; + } + + return null; + } + + private toStringOrUndefined = (value: string | string[] | undefined | null) => + value ? value.toString() : undefined; + + private toFloatOrNull = (value: string | string[] | undefined | null) => + value ? parseFloat(value.toString()) : null; + + getSaleorHeaders() { + return { + domain: this.toStringOrUndefined(this.adapter.getHeader(SALEOR_DOMAIN_HEADER)), + authorizationBearer: this.toStringOrUndefined( + this.adapter.getHeader(SALEOR_AUTHORIZATION_BEARER_HEADER) + ), + signature: this.toStringOrUndefined(this.adapter.getHeader(SALEOR_SIGNATURE_HEADER)), + event: this.toStringOrUndefined(this.adapter.getHeader(SALEOR_EVENT_HEADER)), + saleorApiUrl: this.toStringOrUndefined(this.adapter.getHeader(SALEOR_API_URL_HEADER)), + schemaVersion: this.toFloatOrNull(this.adapter.getHeader(SALEOR_SCHEMA_VERSION)), + }; + } +} diff --git a/src/handlers/shared/generic-adapter-use-case-types.ts b/src/handlers/shared/generic-adapter-use-case-types.ts index ae8b5dab..90077608 100644 --- a/src/handlers/shared/generic-adapter-use-case-types.ts +++ b/src/handlers/shared/generic-adapter-use-case-types.ts @@ -2,9 +2,20 @@ import { AwsLambdaHandlerInput } from "../aws-lambda/platform-adapter"; import { WebApiHandlerInput } from "../fetch-api/platform-adapter"; import { NextJsHandlerInput } from "../next/platform-adapter"; +export const HTTPMethod = { + GET: "GET", + POST: "POST", + PUT: "PUT", + PATH: "PATCH", + HEAD: "HEAD", + OPTIONS: "OPTIONS", + DELETE: "DELETE", +} as const; +export type HTTPMethod = typeof HTTPMethod[keyof typeof HTTPMethod]; + /** Status code of the result, for most platforms it's mapped to HTTP status code * however when request is not HTTP it can be mapped to something else */ -export type ResultStatusCodes = 200 | 201 | 400 | 401 | 403 | 404 | 500 | 503; +export type ResultStatusCodes = 200 | 201 | 400 | 401 | 403 | 404 | 405 | 500 | 503; /** Shape of result that should be returned from use case * that is then translated by adapter to a valid platform response */ @@ -24,11 +35,11 @@ export type HandlerUseCaseResult = * Interface for adapters that translate specific platform objects (e.g. Web API, Next.js) * into a common interface that can be used in each handler use case * */ -export interface PlatformAdapterInterface { +export interface PlatformAdapterInterface { send(result: HandlerUseCaseResult): unknown; getHeader(name: string): string | null; getBody(): Promise; - method: string; + method: HTTPMethod; request: T; } diff --git a/src/handlers/shared/manifest-use-case.ts b/src/handlers/shared/register-use-case.ts similarity index 90% rename from src/handlers/shared/manifest-use-case.ts rename to src/handlers/shared/register-use-case.ts index a1d106dd..93d7d37d 100644 --- a/src/handlers/shared/manifest-use-case.ts +++ b/src/handlers/shared/register-use-case.ts @@ -5,6 +5,7 @@ import { createDebug } from "../../debug"; import { fetchRemoteJwks } from "../../fetch-remote-jwks"; import { getAppId } from "../../get-app-id"; import { HasAPL } from "../../saleor-app"; +import { PlatformAdapterMiddleware } from "./adapter-middleware"; import { HandlerInput, HandlerUseCaseInterface, @@ -130,9 +131,11 @@ export type GenericCreateAppRegisterHandlerOptions = Has ): Promise; }; -export class ManifestUseCase implements HandlerUseCaseInterface { +export class RegisterUseCase implements HandlerUseCaseInterface { private adapter: PlatformAdapterInterface; + private adapterMiddleware: PlatformAdapterMiddleware; + public config: GenericCreateAppRegisterHandlerOptions; constructor({ @@ -143,9 +146,25 @@ export class ManifestUseCase implements HandlerUseCaseIn config: GenericCreateAppRegisterHandlerOptions; }) { this.adapter = adapter; + this.adapterMiddleware = new PlatformAdapterMiddleware(adapter); this.config = config; } + private runPreChecks(): HandlerUseCaseResult | null { + const checksToRun = [ + this.adapterMiddleware.withMethod(["POST"]), + this.adapterMiddleware.withSaleorDomainPresent(), + ]; + + for (const check of checksToRun) { + if (check) { + return check; + } + } + + return null; + } + /** TODO: Add missing retes methods: * withMethod("POST"), * withSaleorDomainPresent, @@ -155,6 +174,11 @@ export class ManifestUseCase implements HandlerUseCaseIn async getResult(): Promise { debug("Request received"); + const precheckResult = this.runPreChecks(); + if (precheckResult) { + return precheckResult; + } + const saleorDomain = this.adapter.getHeader(SALEOR_DOMAIN_HEADER) as string; const saleorApiUrl = this.adapter.getHeader(SALEOR_API_URL_HEADER) as string; @@ -168,6 +192,16 @@ export class ManifestUseCase implements HandlerUseCaseIn const authToken = body.auth_token; + if (!authToken) { + debug("Found missing authToken param"); + + return { + status: 400, + body: "Missing auth token.", + bodyType: "string", + }; + } + if (this.config.onRequestStart) { debug("Calling \"onRequestStart\" hook"); From 25c7d8939f4d43406192b5cdb62b2f6c4a25185d Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Wed, 15 Jan 2025 16:02:24 +0100 Subject: [PATCH 25/58] Fix TS error --- src/handlers/aws-lambda/platform-adapter.ts | 5 +++-- src/handlers/next/create-app-register-handler.test.ts | 4 ++-- src/handlers/shared/register-use-case.ts | 6 +++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/handlers/aws-lambda/platform-adapter.ts b/src/handlers/aws-lambda/platform-adapter.ts index f1385043..5450ecc4 100644 --- a/src/handlers/aws-lambda/platform-adapter.ts +++ b/src/handlers/aws-lambda/platform-adapter.ts @@ -2,6 +2,7 @@ import type { APIGatewayProxyEventV2, APIGatewayProxyResultV2, Context } from "a import { HandlerUseCaseResult, + HTTPMethod, PlatformAdapterInterface, } from "../shared/generic-adapter-use-case-types"; @@ -30,8 +31,8 @@ export class AwsLambdaAdapter implements PlatformAdapterInterface { diff --git a/src/handlers/next/create-app-register-handler.test.ts b/src/handlers/next/create-app-register-handler.test.ts index 709ed0f9..6298a527 100644 --- a/src/handlers/next/create-app-register-handler.test.ts +++ b/src/handlers/next/create-app-register-handler.test.ts @@ -85,7 +85,7 @@ describe("create-app-register-handler", () => { await handler(req, res); expect(res._getStatusCode()).toBe(403); - expect(res._getData().success).toBe(false); + expect(res._getJSONData().success).toBe(false); }); describe("Callback hooks", () => { @@ -246,7 +246,7 @@ describe("create-app-register-handler", () => { await handler(req, res); expect(res._getStatusCode()).toBe(401); - expect(res._getData()).toEqual({ + expect(res._getJSONData()).toEqual({ success: false, error: { code: "REGISTER_HANDLER_HOOK_ERROR", diff --git a/src/handlers/shared/register-use-case.ts b/src/handlers/shared/register-use-case.ts index 93d7d37d..8825ec8c 100644 --- a/src/handlers/shared/register-use-case.ts +++ b/src/handlers/shared/register-use-case.ts @@ -20,7 +20,7 @@ const debug = createDebug("createAppRegisterHandler"); // TODO: Make this private methods? // Copy pasted from existing manifest handler class RegisterCallbackError extends Error { - public status = 500; + public status: ResultStatusCodes = 500; constructor(errorParams: HookCallbackErrorParams) { super(errorParams.message); @@ -44,7 +44,7 @@ export const createRegisterHandlerResponseBody = ( error?: RegisterHandlerResponseBody["error"], statusCode?: ResultStatusCodes ): HandlerUseCaseResult => ({ - status: statusCode ?? success ? 200 : 500, + status: statusCode ?? (success ? 200 : 500), body: { success, error, @@ -71,7 +71,7 @@ const createCallbackError: CallbackErrorHandler = (params: HookCallbackErrorPara }; export type HookCallbackErrorParams = { - status?: number; + status?: ResultStatusCodes; message?: string; }; From f0bfe5fe7d6c1ab8555619f7652cb56932c20c19 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Wed, 15 Jan 2025 16:03:44 +0100 Subject: [PATCH 26/58] Fix status not being sent --- src/handlers/shared/register-use-case.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/handlers/shared/register-use-case.ts b/src/handlers/shared/register-use-case.ts index 8825ec8c..6aa2e5e0 100644 --- a/src/handlers/shared/register-use-case.ts +++ b/src/handlers/shared/register-use-case.ts @@ -54,10 +54,14 @@ export const createRegisterHandlerResponseBody = ( const handleHookError = (e: RegisterCallbackError | unknown): HandlerUseCaseResult => { if (e instanceof RegisterCallbackError) { - return createRegisterHandlerResponseBody(false, { - code: "REGISTER_HANDLER_HOOK_ERROR", - message: e.message, - }); + return createRegisterHandlerResponseBody( + false, + { + code: "REGISTER_HANDLER_HOOK_ERROR", + message: e.message, + }, + e.status + ); } return { status: 500, From 972708bd992cabbed66f474ca1e77ac246b0e1e0 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Thu, 16 Jan 2025 13:57:20 +0100 Subject: [PATCH 27/58] Make aws-lambda peer dependency not strict, make @types/aws-lambda dev dependency --- package.json | 5 ++--- pnpm-lock.yaml | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 7375a874..c019c506 100644 --- a/package.json +++ b/package.json @@ -21,9 +21,8 @@ "author": "", "license": "ISC", "peerDependencies": { - "@types/aws-lambda": "8.10.147", "@vercel/kv": "^1.0.0", - "aws-lambda": "1.0.7", + "aws-lambda": "^1.0.7", "graphql": ">=16.6.0", "next": ">=12", "react": ">=17", @@ -42,7 +41,7 @@ "@changesets/cli": "2.27.1", "@testing-library/dom": "^8.17.1", "@testing-library/react": "^13.4.0", - "@types/aws-lambda": "8.10.147", + "@types/aws-lambda": "^8.10.147", "@types/debug": "^4.1.7", "@types/node": "^18.7.15", "@types/react": "18.0.21", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4800cce4..9e35893f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -38,7 +38,7 @@ devDependencies: specifier: ^13.4.0 version: 13.4.0(react-dom@18.2.0)(react@18.2.0) '@types/aws-lambda': - specifier: 8.10.147 + specifier: ^8.10.147 version: 8.10.147 '@types/debug': specifier: ^4.1.7 From ebd74059bf13166fd173fb8ebd9e384323a6c9c0 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 17 Jan 2025 11:42:23 +0100 Subject: [PATCH 28/58] Refactor register use-case -> action handler --- .../aws-lambda/create-app-register.ts | 9 +- src/handlers/aws-lambda/platform-adapter.ts | 4 +- .../fetch-api/create-app-register-handler.ts | 9 +- src/handlers/fetch-api/platform-adapter.ts | 4 +- .../next/create-app-register-handler.ts | 9 +- src/handlers/next/platform-adapter.ts | 6 +- src/handlers/shared/adapter-middleware.ts | 6 +- .../shared/generic-adapter-use-case-types.ts | 11 +- ...use-case.ts => register-action-handler.ts} | 275 ++++++++++++++---- 9 files changed, 246 insertions(+), 87 deletions(-) rename src/handlers/shared/{register-use-case.ts => register-action-handler.ts} (56%) diff --git a/src/handlers/aws-lambda/create-app-register.ts b/src/handlers/aws-lambda/create-app-register.ts index dbb5de0e..3e9b7b3b 100644 --- a/src/handlers/aws-lambda/create-app-register.ts +++ b/src/handlers/aws-lambda/create-app-register.ts @@ -1,7 +1,10 @@ import { APIGatewayProxyEventV2, Context } from "aws-lambda"; import { GenericCreateAppRegisterHandlerOptions } from "../shared/create-app-register-handler-types"; -import { RegisterHandlerResponseBody, RegisterUseCase } from "../shared/register-use-case"; +import { + RegisterActionHandler, + RegisterHandlerResponseBody, +} from "../shared/register-action-handler"; import { AwsLambdaAdapter, AWSLambdaHandler, AwsLambdaHandlerInput } from "./platform-adapter"; export const createRegisterHandlerResponseBody = ( @@ -19,7 +22,7 @@ export const createAppRegisterHandler = (config: CreateAppRegisterHandlerOptions): AWSLambdaHandler => async (event: APIGatewayProxyEventV2, context: Context) => { const adapter = new AwsLambdaAdapter(event, context); - const useCase = new RegisterUseCase({ adapter, config }); - const result = await useCase.getResult(); + const useCase = new RegisterActionHandler(adapter); + const result = await useCase.handleAction(config); return adapter.send(result); }; diff --git a/src/handlers/aws-lambda/platform-adapter.ts b/src/handlers/aws-lambda/platform-adapter.ts index 5450ecc4..fa61b215 100644 --- a/src/handlers/aws-lambda/platform-adapter.ts +++ b/src/handlers/aws-lambda/platform-adapter.ts @@ -1,7 +1,7 @@ import type { APIGatewayProxyEventV2, APIGatewayProxyResultV2, Context } from "aws-lambda"; import { - HandlerUseCaseResult, + ActionHandlerResult, HTTPMethod, PlatformAdapterInterface, } from "../shared/generic-adapter-use-case-types"; @@ -35,7 +35,7 @@ export class AwsLambdaAdapter implements PlatformAdapterInterface { + async send(result: ActionHandlerResult): Promise { const body = result.bodyType === "json" ? JSON.stringify(result.body) : result.body; return { diff --git a/src/handlers/fetch-api/create-app-register-handler.ts b/src/handlers/fetch-api/create-app-register-handler.ts index 80aa1c4e..49641fa0 100644 --- a/src/handlers/fetch-api/create-app-register-handler.ts +++ b/src/handlers/fetch-api/create-app-register-handler.ts @@ -1,5 +1,8 @@ import { GenericCreateAppRegisterHandlerOptions } from "../shared/create-app-register-handler-types"; -import { RegisterHandlerResponseBody, RegisterUseCase } from "../shared/register-use-case"; +import { + RegisterActionHandler, + RegisterHandlerResponseBody, +} from "../shared/register-action-handler"; import { WebApiAdapter, WebApiHandler, WebApiHandlerInput } from "./platform-adapter"; export const createRegisterHandlerResponseBody = ( @@ -17,7 +20,7 @@ export const createAppRegisterHandler = (config: CreateAppRegisterHandlerOptions): WebApiHandler => async (req: Request) => { const adapter = new WebApiAdapter(req); - const useCase = new RegisterUseCase({ adapter, config }); - const result = await useCase.getResult(); + const useCase = new RegisterActionHandler(adapter); + const result = await useCase.handleAction(config); return adapter.send(result); }; diff --git a/src/handlers/fetch-api/platform-adapter.ts b/src/handlers/fetch-api/platform-adapter.ts index 1e00c0c0..83273a76 100644 --- a/src/handlers/fetch-api/platform-adapter.ts +++ b/src/handlers/fetch-api/platform-adapter.ts @@ -1,5 +1,5 @@ import { - HandlerUseCaseResult, + ActionHandlerResult, PlatformAdapterInterface, } from "../shared/generic-adapter-use-case-types"; @@ -26,7 +26,7 @@ export class WebApiAdapter implements PlatformAdapterInterface { + async send(result: ActionHandlerResult): Promise { const body = result.bodyType === "json" ? JSON.stringify(result.body) : result.body; return new Response(body, { diff --git a/src/handlers/next/create-app-register-handler.ts b/src/handlers/next/create-app-register-handler.ts index 3b76134f..e17ff6e6 100644 --- a/src/handlers/next/create-app-register-handler.ts +++ b/src/handlers/next/create-app-register-handler.ts @@ -1,7 +1,10 @@ import { NextApiRequest, NextApiResponse } from "next"; import { GenericCreateAppRegisterHandlerOptions } from "../shared/create-app-register-handler-types"; -import { RegisterHandlerResponseBody, RegisterUseCase } from "../shared/register-use-case"; +import { + RegisterActionHandler, + RegisterHandlerResponseBody, +} from "../shared/register-action-handler"; import { NextJsAdapter, NextJsHandlerInput } from "./platform-adapter"; // Re-export types for backwards compatibility @@ -24,7 +27,7 @@ export const createAppRegisterHandler = (config: CreateAppRegisterHandlerOptions) => async (req: NextApiRequest, res: NextApiResponse) => { const adapter = new NextJsAdapter(req, res); - const useCase = new RegisterUseCase({ adapter, config }); - const result = await useCase.getResult(); + const useCase = new RegisterActionHandler(adapter); + const result = await useCase.handleAction(config); return adapter.send(result); }; diff --git a/src/handlers/next/platform-adapter.ts b/src/handlers/next/platform-adapter.ts index cfb8b235..6222b64b 100644 --- a/src/handlers/next/platform-adapter.ts +++ b/src/handlers/next/platform-adapter.ts @@ -1,7 +1,7 @@ import { NextApiRequest, NextApiResponse } from "next"; import { - HandlerUseCaseResult, + ActionHandlerResult, PlatformAdapterInterface, } from "../shared/generic-adapter-use-case-types"; @@ -9,7 +9,7 @@ export type NextJsHandlerInput = NextApiRequest; export type NextJsHandler = ( req: NextApiRequest, res: NextApiResponse -) => Promise; +) => Promise; export class NextJsAdapter implements PlatformAdapterInterface { readonly type = "next" as const; @@ -29,7 +29,7 @@ export class NextJsAdapter implements PlatformAdapterInterface { + async send(result: ActionHandlerResult): Promise { if (result.bodyType === "json") { this.res.status(result.status).json(result.body); } else { diff --git a/src/handlers/shared/adapter-middleware.ts b/src/handlers/shared/adapter-middleware.ts index e22c1ec6..0576d1e4 100644 --- a/src/handlers/shared/adapter-middleware.ts +++ b/src/handlers/shared/adapter-middleware.ts @@ -8,7 +8,7 @@ import { } from "../../const"; import { createMiddlewareDebug } from "../../middleware/middleware-debug"; import { - HandlerUseCaseResult, + ActionHandlerResult, HTTPMethod, PlatformAdapterInterface, } from "./generic-adapter-use-case-types"; @@ -18,7 +18,7 @@ const debug = createMiddlewareDebug("PlatformAdapterMiddleware"); export class PlatformAdapterMiddleware { constructor(private adapter: PlatformAdapterInterface) {} - withMethod(methods: HTTPMethod[]): HandlerUseCaseResult | null { + withMethod(methods: HTTPMethod[]): ActionHandlerResult | null { if (!methods.includes(this.adapter.method)) { return { body: "Method not allowed", @@ -30,7 +30,7 @@ export class PlatformAdapterMiddleware { return null; } - withSaleorDomainPresent(): HandlerUseCaseResult | null { + withSaleorDomainPresent(): ActionHandlerResult | null { const { domain } = this.getSaleorHeaders(); debug("withSaleorDomainPresent middleware called with domain in header: %s", domain); diff --git a/src/handlers/shared/generic-adapter-use-case-types.ts b/src/handlers/shared/generic-adapter-use-case-types.ts index 90077608..bdc3f5d1 100644 --- a/src/handlers/shared/generic-adapter-use-case-types.ts +++ b/src/handlers/shared/generic-adapter-use-case-types.ts @@ -19,7 +19,7 @@ export type ResultStatusCodes = 200 | 201 | 400 | 401 | 403 | 404 | 405 | 500 | /** Shape of result that should be returned from use case * that is then translated by adapter to a valid platform response */ -export type HandlerUseCaseResult = +export type ActionHandlerResult = | { status: ResultStatusCodes; body: Body; @@ -35,8 +35,8 @@ export type HandlerUseCaseResult = * Interface for adapters that translate specific platform objects (e.g. Web API, Next.js) * into a common interface that can be used in each handler use case * */ -export interface PlatformAdapterInterface { - send(result: HandlerUseCaseResult): unknown; +export interface PlatformAdapterInterface { + send(result: ActionHandlerResult): unknown; getHeader(name: string): string | null; getBody(): Promise; method: HTTPMethod; @@ -45,8 +45,9 @@ export interface PlatformAdapterInterface /** Interfaces for use case handlers that encapsulate business logic * (e.g. validating headers, checking HTTP method, etc. ) */ -export interface HandlerUseCaseInterface { - getResult(): Promise; +export interface ActionHandlerInterface { + handleAction(...params: any): Promise; } +// TODO: remove export type HandlerInput = NextJsHandlerInput | WebApiHandlerInput | AwsLambdaHandlerInput; diff --git a/src/handlers/shared/register-use-case.ts b/src/handlers/shared/register-action-handler.ts similarity index 56% rename from src/handlers/shared/register-use-case.ts rename to src/handlers/shared/register-action-handler.ts index 6aa2e5e0..abf9f994 100644 --- a/src/handlers/shared/register-use-case.ts +++ b/src/handlers/shared/register-action-handler.ts @@ -1,5 +1,5 @@ /* eslint-disable max-classes-per-file */ -import { AuthData } from "../../APL"; +import { APL, AuthData } from "../../APL"; import { SALEOR_API_URL_HEADER, SALEOR_DOMAIN_HEADER } from "../../const"; import { createDebug } from "../../debug"; import { fetchRemoteJwks } from "../../fetch-remote-jwks"; @@ -7,9 +7,9 @@ import { getAppId } from "../../get-app-id"; import { HasAPL } from "../../saleor-app"; import { PlatformAdapterMiddleware } from "./adapter-middleware"; import { + ActionHandlerInterface, + ActionHandlerResult, HandlerInput, - HandlerUseCaseInterface, - HandlerUseCaseResult, PlatformAdapterInterface, ResultStatusCodes, } from "./generic-adapter-use-case-types"; @@ -43,7 +43,7 @@ export const createRegisterHandlerResponseBody = ( success: boolean, error?: RegisterHandlerResponseBody["error"], statusCode?: ResultStatusCodes -): HandlerUseCaseResult => ({ +): ActionHandlerResult => ({ status: statusCode ?? (success ? 200 : 500), body: { success, @@ -52,7 +52,7 @@ export const createRegisterHandlerResponseBody = ( bodyType: "json", }); -const handleHookError = (e: RegisterCallbackError | unknown): HandlerUseCaseResult => { +const handleHookError = (e: RegisterCallbackError | unknown): ActionHandlerResult => { if (e instanceof RegisterCallbackError) { return createRegisterHandlerResponseBody( false, @@ -81,7 +81,7 @@ export type HookCallbackErrorParams = { export type CallbackErrorHandler = (params: HookCallbackErrorParams) => never; -export type GenericCreateAppRegisterHandlerOptions = HasAPL & { +export type AppRegisterHandlerOptions = HasAPL & { /** * Protect app from being registered in Saleor other than specific. * By default, allow everything. @@ -135,26 +135,12 @@ export type GenericCreateAppRegisterHandlerOptions = Has ): Promise; }; -export class RegisterUseCase implements HandlerUseCaseInterface { - private adapter: PlatformAdapterInterface; +export class RegisterActionHandler implements ActionHandlerInterface { + private adapterMiddleware = new PlatformAdapterMiddleware(this.adapter); - private adapterMiddleware: PlatformAdapterMiddleware; + constructor(private adapter: PlatformAdapterInterface) {} - public config: GenericCreateAppRegisterHandlerOptions; - - constructor({ - adapter, - config, - }: { - adapter: PlatformAdapterInterface; - config: GenericCreateAppRegisterHandlerOptions; - }) { - this.adapter = adapter; - this.adapterMiddleware = new PlatformAdapterMiddleware(adapter); - this.config = config; - } - - private runPreChecks(): HandlerUseCaseResult | null { + private runPreChecks(): ActionHandlerResult | null { const checksToRun = [ this.adapterMiddleware.withMethod(["POST"]), this.adapterMiddleware.withSaleorDomainPresent(), @@ -169,13 +155,7 @@ export class RegisterUseCase implements HandlerUseCaseIn return null; } - /** TODO: Add missing retes methods: - * withMethod("POST"), - * withSaleorDomainPresent, - * withAuthTokenRequired, - * baseHandler, - * */ - async getResult(): Promise { + async handleAction(config: AppRegisterHandlerOptions): Promise { debug("Request received"); const precheckResult = this.runPreChecks(); @@ -186,31 +166,147 @@ export class RegisterUseCase implements HandlerUseCaseIn const saleorDomain = this.adapter.getHeader(SALEOR_DOMAIN_HEADER) as string; const saleorApiUrl = this.adapter.getHeader(SALEOR_API_URL_HEADER) as string; + const authTokenResult = await this.parseRequestBody(); + + if (!authTokenResult.success) { + return authTokenResult.response; + } + + const { authToken } = authTokenResult; + + const handleOnRequestResult = await this.handleOnRequestStartCallback(config.onRequestStart, { + authToken, + saleorApiUrl, + saleorDomain, + }); + + if (handleOnRequestResult) { + return handleOnRequestResult; + } + + if (!saleorApiUrl) { + // TODO: We should strictly require `saleorApiUrl` instead of + // relying on `saleor-domain` that is deprecated + debug("saleorApiUrl doesn't exist in headers"); + } + + const saleorApiUrlValidationResult = this.handleSaleorApiUrlValidation({ + saleorApiUrl, + allowedSaleorUrls: config.allowedSaleorUrls, + }); + + if (saleorApiUrlValidationResult) { + return saleorApiUrlValidationResult; + } + + const aplCheckResult = await this.checkAplIsConfigured(config.apl); + + if (aplCheckResult) { + return aplCheckResult; + } + + const getAppIdResult = await this.getAppIdAndHandleMissingAppId({ + saleorApiUrl, + token: authToken, + }); + + if (!getAppIdResult.success) { + return getAppIdResult.responseBody; + } + + const { appId } = getAppIdResult; + + const getJwksResult = await this.getJwksAndHandleMissingJwks({ saleorApiUrl }); + + if (!getJwksResult.success) { + return getJwksResult.responseBody; + } + + const { jwks } = getJwksResult; + + const authData = { + domain: saleorDomain, + token: authToken, + saleorApiUrl, + appId, + jwks, + }; + + const onRequestVerifiedErrorResponse = await this.handleOnRequestVerifiedCallback( + config.onRequestVerified, + authData + ); + + if (onRequestVerifiedErrorResponse) { + return onRequestVerifiedErrorResponse; + } + + const aplSaveResponse = await this.saveAplAuthData({ + apl: config.apl, + authData, + onAplSetFailed: config.onAplSetFailed, + onAuthAplSaved: config.onAuthAplSaved, + }); + + return aplSaveResponse; + } + + private async parseRequestBody(): Promise< + | { success: false; response: ActionHandlerResult; authToken?: never } + | { + success: true; + authToken: string; + response?: never; + } + > { let body: { auth_token: string }; try { body = (await this.adapter.getBody()) as { auth_token: string }; } catch (err) { - // TODO: Handle error - throw new Error("Cannot parse body"); + return { + success: false, + response: { + status: 400, + body: "Invalid request json.", + bodyType: "string", + }, + }; } - const authToken = body.auth_token; + const authToken = body?.auth_token; if (!authToken) { debug("Found missing authToken param"); return { - status: 400, - body: "Missing auth token.", - bodyType: "string", + success: false, + response: { + status: 400, + body: "Missing auth token.", + bodyType: "string", + }, }; } - if (this.config.onRequestStart) { + return { + success: true, + authToken, + }; + } + + private async handleOnRequestStartCallback( + onRequestStart: AppRegisterHandlerOptions["onRequestStart"], + { + authToken, + saleorApiUrl, + saleorDomain, + }: { authToken: string; saleorApiUrl: string; saleorDomain: string } + ) { + if (onRequestStart) { debug("Calling \"onRequestStart\" hook"); try { - await this.config.onRequestStart(this.adapter.request, { + await onRequestStart(this.adapter.request, { authToken, saleorApiUrl, saleorDomain, @@ -223,11 +319,18 @@ export class RegisterUseCase implements HandlerUseCaseIn } } - if (!saleorApiUrl) { - debug("saleorApiUrl doesn't exist in headers"); - } + // If everything is fine we can proceed handling action + return null; + } - if (!validateAllowSaleorUrls(saleorApiUrl, this.config.allowedSaleorUrls)) { + private handleSaleorApiUrlValidation({ + saleorApiUrl, + allowedSaleorUrls, + }: { + saleorApiUrl: string; + allowedSaleorUrls: AppRegisterHandlerOptions["allowedSaleorUrls"]; + }) { + if (!validateAllowSaleorUrls(saleorApiUrl, allowedSaleorUrls)) { debug( "Validation of URL %s against allowSaleorUrls param resolves to false, throwing", saleorApiUrl @@ -243,7 +346,11 @@ export class RegisterUseCase implements HandlerUseCaseIn ); } - const { configured: aplConfigured } = await this.config.apl.isConfigured(); + return null; + } + + private async checkAplIsConfigured(apl: AppRegisterHandlerOptions["apl"]) { + const { configured: aplConfigured } = await apl.isConfigured(); if (!aplConfigured) { debug("The APL has not been configured"); @@ -258,10 +365,27 @@ export class RegisterUseCase implements HandlerUseCaseIn ); } + return null; + } + + private async getAppIdAndHandleMissingAppId({ + saleorApiUrl, + token, + }: { + saleorApiUrl: string; + token: string; + }): Promise< + | { + success: false; + responseBody: ActionHandlerResult; + } + | { success: true; appId: string } + > { // Try to get App ID from the API, to confirm that communication can be established - const appId = await getAppId({ saleorApiUrl, token: authToken }); + const appId = await getAppId({ saleorApiUrl, token }); + if (!appId) { - return createRegisterHandlerResponseBody( + const responseBody = createRegisterHandlerResponseBody( false, { code: "UNKNOWN_APP_ID", @@ -270,12 +394,24 @@ export class RegisterUseCase implements HandlerUseCaseIn }, 401 ); + + return { success: false, responseBody }; } + return { success: true, appId }; + } + + private async getJwksAndHandleMissingJwks({ saleorApiUrl }: { saleorApiUrl: string }): Promise< + | { + success: false; + responseBody: ActionHandlerResult; + } + | { success: true; jwks: string } + > { // Fetch the JWKS which will be used during webhook validation const jwks = await fetchRemoteJwks(saleorApiUrl); if (!jwks) { - return createRegisterHandlerResponseBody( + const responseBody = createRegisterHandlerResponseBody( false, { code: "JWKS_NOT_AVAILABLE", @@ -283,21 +419,21 @@ export class RegisterUseCase implements HandlerUseCaseIn }, 401 ); - } - const authData = { - domain: saleorDomain, - token: authToken, - saleorApiUrl, - appId, - jwks, - }; + return { success: false, responseBody }; + } + return { success: true, jwks }; + } - if (this.config.onRequestVerified) { + private async handleOnRequestVerifiedCallback( + onRequestVerified: AppRegisterHandlerOptions["onRequestVerified"], + authData: AuthData + ) { + if (onRequestVerified) { debug("Calling \"onRequestVerified\" hook"); try { - await this.config.onRequestVerified(this.adapter.request, { + await onRequestVerified(this.adapter.request, { authData, respondWithError: createCallbackError, }); @@ -308,14 +444,28 @@ export class RegisterUseCase implements HandlerUseCaseIn } } + return null; + } + + private async saveAplAuthData({ + apl, + onAplSetFailed, + onAuthAplSaved, + authData, + }: { + apl: APL; + onAplSetFailed: AppRegisterHandlerOptions["onAplSetFailed"]; + onAuthAplSaved: AppRegisterHandlerOptions["onAuthAplSaved"]; + authData: AuthData; + }) { try { - await this.config.apl.set(authData); + await apl.set(authData); - if (this.config.onAuthAplSaved) { + if (onAuthAplSaved) { debug("Calling \"onAuthAplSaved\" hook"); try { - await this.config.onAuthAplSaved(this.adapter.request, { + await onAuthAplSaved(this.adapter.request, { authData, respondWithError: createCallbackError, }); @@ -328,11 +478,11 @@ export class RegisterUseCase implements HandlerUseCaseIn } catch (aplError: unknown) { debug("There was an error during saving the auth data"); - if (this.config.onAplSetFailed) { + if (onAplSetFailed) { debug("Calling \"onAuthAplFailed\" hook"); try { - await this.config.onAplSetFailed(this.adapter.request, { + await onAplSetFailed(this.adapter.request, { authData, error: aplError, respondWithError: createCallbackError, @@ -350,7 +500,6 @@ export class RegisterUseCase implements HandlerUseCaseIn } debug("Register complete"); - return createRegisterHandlerResponseBody(true); } } From 2833043a224a15208213a832e32e9068e812c3bf Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 17 Jan 2025 11:59:56 +0100 Subject: [PATCH 29/58] Remove top level functions, add to class --- .../shared/register-action-handler.ts | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/handlers/shared/register-action-handler.ts b/src/handlers/shared/register-action-handler.ts index abf9f994..e20632e4 100644 --- a/src/handlers/shared/register-action-handler.ts +++ b/src/handlers/shared/register-action-handler.ts @@ -17,8 +17,8 @@ import { validateAllowSaleorUrls } from "./validate-allow-saleor-urls"; const debug = createDebug("createAppRegisterHandler"); -// TODO: Make this private methods? -// Copy pasted from existing manifest handler +/** Error raised by async handlers passed by + * users in config to Register handler */ class RegisterCallbackError extends Error { public status: ResultStatusCodes = 500; @@ -52,28 +52,6 @@ export const createRegisterHandlerResponseBody = ( bodyType: "json", }); -const handleHookError = (e: RegisterCallbackError | unknown): ActionHandlerResult => { - if (e instanceof RegisterCallbackError) { - return createRegisterHandlerResponseBody( - false, - { - code: "REGISTER_HANDLER_HOOK_ERROR", - message: e.message, - }, - e.status - ); - } - return { - status: 500, - body: "Error during app installation", - bodyType: "string", - }; -}; - -const createCallbackError: CallbackErrorHandler = (params: HookCallbackErrorParams) => { - throw new RegisterCallbackError(params); -}; - export type HookCallbackErrorParams = { status?: ResultStatusCodes; message?: string; @@ -310,12 +288,12 @@ export class RegisterActionHandler implements ActionHand authToken, saleorApiUrl, saleorDomain, - respondWithError: createCallbackError, + respondWithError: this.createCallbackError, }); } catch (e: RegisterCallbackError | unknown) { debug("\"onRequestStart\" hook thrown error: %o", e); - return handleHookError(e); + return this.handleHookError(e); } } @@ -435,12 +413,12 @@ export class RegisterActionHandler implements ActionHand try { await onRequestVerified(this.adapter.request, { authData, - respondWithError: createCallbackError, + respondWithError: this.createCallbackError, }); } catch (e: RegisterCallbackError | unknown) { debug("\"onRequestVerified\" hook thrown error: %o", e); - return handleHookError(e); + return this.handleHookError(e); } } @@ -467,12 +445,12 @@ export class RegisterActionHandler implements ActionHand try { await onAuthAplSaved(this.adapter.request, { authData, - respondWithError: createCallbackError, + respondWithError: this.createCallbackError, }); } catch (e: RegisterCallbackError | unknown) { debug("\"onAuthAplSaved\" hook thrown error: %o", e); - return handleHookError(e); + return this.handleHookError(e); } } } catch (aplError: unknown) { @@ -485,12 +463,12 @@ export class RegisterActionHandler implements ActionHand await onAplSetFailed(this.adapter.request, { authData, error: aplError, - respondWithError: createCallbackError, + respondWithError: this.createCallbackError, }); } catch (hookError: RegisterCallbackError | unknown) { debug("\"onAuthAplFailed\" hook thrown error: %o", hookError); - return handleHookError(hookError); + return this.handleHookError(hookError); } } @@ -502,4 +480,26 @@ export class RegisterActionHandler implements ActionHand debug("Register complete"); return createRegisterHandlerResponseBody(true); } + + private handleHookError(e: RegisterCallbackError | unknown): ActionHandlerResult { + if (e instanceof RegisterCallbackError) { + return createRegisterHandlerResponseBody( + false, + { + code: "REGISTER_HANDLER_HOOK_ERROR", + message: e.message, + }, + e.status + ); + } + return { + status: 500, + body: "Error during app installation", + bodyType: "string", + }; + } + + private createCallbackError: CallbackErrorHandler = (params: HookCallbackErrorParams) => { + throw new RegisterCallbackError(params); + }; } From 2b0486c05fcb5c946a3d2dfff1d21074dc0b2ded Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 17 Jan 2025 12:02:58 +0100 Subject: [PATCH 30/58] Fix formatting, add comments --- src/handlers/shared/register-action-handler.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/handlers/shared/register-action-handler.ts b/src/handlers/shared/register-action-handler.ts index e20632e4..e432857d 100644 --- a/src/handlers/shared/register-action-handler.ts +++ b/src/handlers/shared/register-action-handler.ts @@ -297,7 +297,6 @@ export class RegisterActionHandler implements ActionHand } } - // If everything is fine we can proceed handling action return null; } @@ -481,6 +480,8 @@ export class RegisterActionHandler implements ActionHand return createRegisterHandlerResponseBody(true); } + /** Callbacks declared by users in configuration can throw an error + * It is caught here and converted into a response */ private handleHookError(e: RegisterCallbackError | unknown): ActionHandlerResult { if (e instanceof RegisterCallbackError) { return createRegisterHandlerResponseBody( From ca7543b65b35deaf75d470dc9be1fdb57f191f33 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 17 Jan 2025 12:03:08 +0100 Subject: [PATCH 31/58] Remove readme file --- src/handlers/next/readme.md | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 src/handlers/next/readme.md diff --git a/src/handlers/next/readme.md b/src/handlers/next/readme.md deleted file mode 100644 index e6cfad4f..00000000 --- a/src/handlers/next/readme.md +++ /dev/null @@ -1,3 +0,0 @@ -Handlers with adapters to Next.js - -TODO Extract to separate package From a63ed595650753f691d3352f8fe79995f52e182e Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 17 Jan 2025 12:07:17 +0100 Subject: [PATCH 32/58] Change TypeScript config to allow build, add export for next-app-router --- package.json | 5 +++++ src/handlers/shared/register-action-handler.ts | 4 ++-- tsconfig.json | 10 +--------- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index c019c506..f1b8cb3f 100644 --- a/package.json +++ b/package.json @@ -149,6 +149,11 @@ "import": "./handlers/fetch-api/index.mjs", "require": "./handlers/fetch-api/index.js" }, + "./handlers/next-app-router": { + "types": "./handlers/fetch-api/index.d.ts", + "import": "./handlers/fetch-api/index.mjs", + "require": "./handlers/fetch-api/index.js" + }, "./handlers/shared": { "types": "./handlers/shared/index.d.ts", "import": "./handlers/shared/index.mjs", diff --git a/src/handlers/shared/register-action-handler.ts b/src/handlers/shared/register-action-handler.ts index e432857d..62e9f7e7 100644 --- a/src/handlers/shared/register-action-handler.ts +++ b/src/handlers/shared/register-action-handler.ts @@ -114,10 +114,10 @@ export type AppRegisterHandlerOptions = HasAPL & { }; export class RegisterActionHandler implements ActionHandlerInterface { - private adapterMiddleware = new PlatformAdapterMiddleware(this.adapter); - constructor(private adapter: PlatformAdapterInterface) {} + private adapterMiddleware = new PlatformAdapterMiddleware(this.adapter); + private runPreChecks(): ActionHandlerResult | null { const checksToRun = [ this.adapterMiddleware.withMethod(["POST"]), diff --git a/tsconfig.json b/tsconfig.json index 504417b7..90fe2d82 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,6 @@ { "compilerOptions": { /* Visit https://aka.ms/tsconfig to read more about this file */ - /* Projects */ // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ @@ -9,7 +8,6 @@ // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - /* Language and Environment */ "target": "ES2021" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, "lib": [ @@ -24,9 +22,8 @@ // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + "useDefineForClassFields": false /* Don't Emit ECMAScript-standard-compliant class fields. - we can use class field initializers, after constructor is run */, // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ - /* Modules */ "module": "commonjs" /* Specify what module code is generated. */, // "rootDir": "./", /* Specify the root folder within your source files. */ @@ -40,12 +37,10 @@ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ "resolveJsonModule": true /* Enable importing .json files. */, // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ - /* JavaScript Support */ // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ - /* Emit */ // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ // "declarationMap": true, /* Create sourcemaps for d.ts files. */ @@ -70,14 +65,12 @@ // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ - /* Interop Constraints */ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, - /* Type Checking */ "strict": true /* Enable all strict type-checking options. */, // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ @@ -98,7 +91,6 @@ // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - /* Completeness */ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ "skipLibCheck": true /* Skip type checking all .d.ts files. */ From 3107c0c6cc5e56d2c348d667af8b1cf20fa9e6c2 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 17 Jan 2025 12:22:10 +0100 Subject: [PATCH 33/58] Removed circular dependencies --- src/handlers/shared/adapter-middleware.ts | 4 ++-- src/handlers/shared/generic-adapter-use-case-types.ts | 7 ------- src/handlers/shared/register-action-handler.ts | 5 ++--- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/handlers/shared/adapter-middleware.ts b/src/handlers/shared/adapter-middleware.ts index 0576d1e4..ec9d4685 100644 --- a/src/handlers/shared/adapter-middleware.ts +++ b/src/handlers/shared/adapter-middleware.ts @@ -15,8 +15,8 @@ import { const debug = createMiddlewareDebug("PlatformAdapterMiddleware"); -export class PlatformAdapterMiddleware { - constructor(private adapter: PlatformAdapterInterface) {} +export class PlatformAdapterMiddleware { + constructor(private adapter: PlatformAdapterInterface) {} withMethod(methods: HTTPMethod[]): ActionHandlerResult | null { if (!methods.includes(this.adapter.method)) { diff --git a/src/handlers/shared/generic-adapter-use-case-types.ts b/src/handlers/shared/generic-adapter-use-case-types.ts index bdc3f5d1..1470e5a4 100644 --- a/src/handlers/shared/generic-adapter-use-case-types.ts +++ b/src/handlers/shared/generic-adapter-use-case-types.ts @@ -1,7 +1,3 @@ -import { AwsLambdaHandlerInput } from "../aws-lambda/platform-adapter"; -import { WebApiHandlerInput } from "../fetch-api/platform-adapter"; -import { NextJsHandlerInput } from "../next/platform-adapter"; - export const HTTPMethod = { GET: "GET", POST: "POST", @@ -48,6 +44,3 @@ export interface PlatformAdapterInterface { export interface ActionHandlerInterface { handleAction(...params: any): Promise; } - -// TODO: remove -export type HandlerInput = NextJsHandlerInput | WebApiHandlerInput | AwsLambdaHandlerInput; diff --git a/src/handlers/shared/register-action-handler.ts b/src/handlers/shared/register-action-handler.ts index 62e9f7e7..1d526516 100644 --- a/src/handlers/shared/register-action-handler.ts +++ b/src/handlers/shared/register-action-handler.ts @@ -9,7 +9,6 @@ import { PlatformAdapterMiddleware } from "./adapter-middleware"; import { ActionHandlerInterface, ActionHandlerResult, - HandlerInput, PlatformAdapterInterface, ResultStatusCodes, } from "./generic-adapter-use-case-types"; @@ -59,7 +58,7 @@ export type HookCallbackErrorParams = { export type CallbackErrorHandler = (params: HookCallbackErrorParams) => never; -export type AppRegisterHandlerOptions = HasAPL & { +export type AppRegisterHandlerOptions = HasAPL & { /** * Protect app from being registered in Saleor other than specific. * By default, allow everything. @@ -113,7 +112,7 @@ export type AppRegisterHandlerOptions = HasAPL & { ): Promise; }; -export class RegisterActionHandler implements ActionHandlerInterface { +export class RegisterActionHandler implements ActionHandlerInterface { constructor(private adapter: PlatformAdapterInterface) {} private adapterMiddleware = new PlatformAdapterMiddleware(this.adapter); From b86b66579ff139eb72a65c41ea8bc4d88575fa64 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 17 Jan 2025 12:22:35 +0100 Subject: [PATCH 34/58] Add virtual export to tsup --- tsup.config.ts | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/tsup.config.ts b/tsup.config.ts index f6e5aa38..ddd23719 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -1,25 +1,28 @@ import { defineConfig } from "tsup"; export default defineConfig({ - entry: [ - "src/const.ts", - "src/types.ts", - "src/urls.ts", - "src/headers.ts", - "src/saleor-app.ts", - "src/verify-jwt.ts", - "src/verify-signature.ts", - "src/APL/index.ts", - "src/APL/vercel-kv/index.ts", - "src/app-bridge/index.ts", - "src/app-bridge/next/index.ts", - "src/handlers/next/index.ts", - "src/handlers/fetch-api/index.ts", - "src/handlers/shared/index.ts", - "src/fetch-middleware/index.ts", - "src/middleware/index.ts", - "src/settings-manager/index.ts", - ], + entry: { + const: "src/const.ts", + types: "src/types.ts", + urls: "src/urls.ts", + headers: "src/headers.ts", + "saleor-app": "src/saleor-app.ts", + "verify-jwt": "src/verify-jwt.ts", + "verify-signature": "src/verify-signature.ts", + "APL/index": "src/APL/index.ts", + "APL/vercel-kv/index": "src/APL/vercel-kv/index.ts", + "app-bridge/index": "src/app-bridge/index.ts", + "app-bridge/next/index": "src/app-bridge/next/index.ts", + "handlers/next/index": "src/handlers/next/index.ts", + "handlers/fetch-api/index": "src/handlers/fetch-api/index.ts", + "handlers/shared/index": "src/handlers/shared/index.ts", + "fetch-middleware/index": "src/fetch-middleware/index.ts", + "middleware/index": "src/middleware/index.ts", + "settings-manager/index": "src/settings-manager/index.ts", + + // Virtual export + "handlers/next-app-router/index": "src/handlers/fetch-api/index.ts", + }, dts: true, clean: true, format: ["esm", "cjs"], From caf7d0fd37ef79b59ddc8e09b28a1600b55d47e6 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 17 Jan 2025 12:23:38 +0100 Subject: [PATCH 35/58] Fix any type warning --- src/handlers/shared/generic-adapter-use-case-types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/handlers/shared/generic-adapter-use-case-types.ts b/src/handlers/shared/generic-adapter-use-case-types.ts index 1470e5a4..92cb6d17 100644 --- a/src/handlers/shared/generic-adapter-use-case-types.ts +++ b/src/handlers/shared/generic-adapter-use-case-types.ts @@ -42,5 +42,5 @@ export interface PlatformAdapterInterface { /** Interfaces for use case handlers that encapsulate business logic * (e.g. validating headers, checking HTTP method, etc. ) */ export interface ActionHandlerInterface { - handleAction(...params: any): Promise; + handleAction(...params: [unknown]): Promise; } From 2726223014a2916e6f9a89625fce87c78c1b509e Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 17 Jan 2025 12:27:28 +0100 Subject: [PATCH 36/58] Fix broken lockfile (old local pnpm version) --- pnpm-lock.yaml | 8306 ++++++++++++++++++++++++++---------------------- 1 file changed, 4540 insertions(+), 3766 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9e35893f..baa55e2b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,1215 +1,719 @@ -lockfileVersion: '6.0' +lockfileVersion: '9.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false -dependencies: - '@opentelemetry/api': - specifier: ^1.7.0 - version: 1.7.0 - '@opentelemetry/semantic-conventions': - specifier: ^1.18.1 - version: 1.18.1 - debug: - specifier: 4.3.4 - version: 4.3.4 - jose: - specifier: 4.14.4 - version: 4.14.4 - raw-body: - specifier: 2.5.2 - version: 2.5.2 - retes: - specifier: 0.33.0 - version: 0.33.0 - uuid: - specifier: 9.0.0 - version: 9.0.0 - -devDependencies: - '@changesets/cli': - specifier: 2.27.1 - version: 2.27.1 - '@testing-library/dom': - specifier: ^8.17.1 - version: 8.17.1 - '@testing-library/react': - specifier: ^13.4.0 - version: 13.4.0(react-dom@18.2.0)(react@18.2.0) - '@types/aws-lambda': - specifier: ^8.10.147 - version: 8.10.147 - '@types/debug': - specifier: ^4.1.7 - version: 4.1.7 - '@types/node': - specifier: ^18.7.15 - version: 18.7.15 - '@types/react': - specifier: 18.0.21 - version: 18.0.21 - '@types/react-dom': - specifier: ^18.0.5 - version: 18.0.6 - '@types/uuid': - specifier: ^8.3.4 - version: 8.3.4 - '@typescript-eslint/eslint-plugin': - specifier: ^5.36.1 - version: 5.36.1(@typescript-eslint/parser@7.1.1)(eslint@8.23.0)(typescript@5.4.2) - '@typescript-eslint/parser': - specifier: ^7.1.1 - version: 7.1.1(eslint@8.23.0)(typescript@5.4.2) - '@vercel/kv': - specifier: 1.0.0 - version: 1.0.0 - '@vitejs/plugin-react': - specifier: ^3.0.1 - version: 3.0.1(vite@4.0.5) - '@vitest/coverage-c8': - specifier: ^0.27.2 - version: 0.27.2(jsdom@20.0.3) - aws-lambda: - specifier: 1.0.7 - version: 1.0.7 - clean-publish: - specifier: ^4.0.1 - version: 4.0.1 - eslint: - specifier: 8.23.0 - version: 8.23.0 - eslint-config-airbnb: - specifier: ^19.0.4 - version: 19.0.4(eslint-plugin-import@2.26.0)(eslint-plugin-jsx-a11y@6.6.1)(eslint-plugin-react-hooks@4.6.0)(eslint-plugin-react@7.31.6)(eslint@8.23.0) - eslint-config-airbnb-typescript: - specifier: ^17.1.0 - version: 17.1.0(@typescript-eslint/eslint-plugin@5.36.1)(@typescript-eslint/parser@7.1.1)(eslint-plugin-import@2.26.0)(eslint@8.23.0) - eslint-config-prettier: - specifier: ^8.5.0 - version: 8.5.0(eslint@8.23.0) - eslint-import-resolver-typescript: - specifier: ^3.5.0 - version: 3.5.0(eslint-plugin-import@2.26.0)(eslint@8.23.0) - eslint-plugin-import: - specifier: ^2.26.0 - version: 2.26.0(@typescript-eslint/parser@7.1.1)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0) - eslint-plugin-jsx-a11y: - specifier: ^6.6.1 - version: 6.6.1(eslint@8.23.0) - eslint-plugin-react: - specifier: ^7.31.6 - version: 7.31.6(eslint@8.23.0) - eslint-plugin-react-hooks: - specifier: ^4.6.0 - version: 4.6.0(eslint@8.23.0) - eslint-plugin-simple-import-sort: - specifier: ^8.0.0 - version: 8.0.0(eslint@8.23.0) - graphql: - specifier: 16.8.0 - version: 16.8.0 - husky: - specifier: ^8.0.1 - version: 8.0.1 - jsdom: - specifier: ^20.0.3 - version: 20.0.3 - lint-staged: - specifier: ^13.0.3 - version: 13.0.3 - next: - specifier: ^12.3.0 - version: 12.3.0(@babel/core@7.20.12)(react-dom@18.2.0)(react@18.2.0) - node-mocks-http: - specifier: ^1.11.0 - version: 1.11.0 - prettier: - specifier: 2.7.1 - version: 2.7.1 - react: - specifier: ^18.2.0 - version: 18.2.0 - react-dom: - specifier: 18.2.0 - version: 18.2.0(react@18.2.0) - tsm: - specifier: ^2.2.2 - version: 2.2.2 - tsup: - specifier: ^6.2.3 - version: 6.2.3(typescript@5.4.2) - typescript: - specifier: 5.4.2 - version: 5.4.2 - vi-fetch: - specifier: ^0.8.0 - version: 0.8.0 - vite: - specifier: ^4.0.4 - version: 4.0.5(@types/node@18.7.15) - vitest: - specifier: ^0.28.1 - version: 0.28.1(jsdom@20.0.3) +importers: + + .: + dependencies: + '@opentelemetry/api': + specifier: ^1.7.0 + version: 1.7.0 + '@opentelemetry/semantic-conventions': + specifier: ^1.18.1 + version: 1.18.1 + debug: + specifier: 4.3.4 + version: 4.3.4 + jose: + specifier: 4.14.4 + version: 4.14.4 + raw-body: + specifier: 2.5.2 + version: 2.5.2 + retes: + specifier: 0.33.0 + version: 0.33.0 + uuid: + specifier: 9.0.0 + version: 9.0.0 + devDependencies: + '@changesets/cli': + specifier: 2.27.1 + version: 2.27.1 + '@testing-library/dom': + specifier: ^8.17.1 + version: 8.17.1 + '@testing-library/react': + specifier: ^13.4.0 + version: 13.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@types/aws-lambda': + specifier: ^8.10.147 + version: 8.10.147 + '@types/debug': + specifier: ^4.1.7 + version: 4.1.7 + '@types/node': + specifier: ^18.7.15 + version: 18.7.15 + '@types/react': + specifier: 18.0.21 + version: 18.0.21 + '@types/react-dom': + specifier: ^18.0.5 + version: 18.0.6 + '@types/uuid': + specifier: ^8.3.4 + version: 8.3.4 + '@typescript-eslint/eslint-plugin': + specifier: ^5.36.1 + version: 5.36.1(@typescript-eslint/parser@7.1.1(eslint@8.23.0)(typescript@5.4.2))(eslint@8.23.0)(typescript@5.4.2) + '@typescript-eslint/parser': + specifier: ^7.1.1 + version: 7.1.1(eslint@8.23.0)(typescript@5.4.2) + '@vercel/kv': + specifier: 1.0.0 + version: 1.0.0 + '@vitejs/plugin-react': + specifier: ^3.0.1 + version: 3.0.1(vite@4.0.5(@types/node@18.7.15)) + '@vitest/coverage-c8': + specifier: ^0.27.2 + version: 0.27.2(jsdom@20.0.3) + aws-lambda: + specifier: 1.0.7 + version: 1.0.7 + clean-publish: + specifier: ^4.0.1 + version: 4.0.1 + eslint: + specifier: 8.23.0 + version: 8.23.0 + eslint-config-airbnb: + specifier: ^19.0.4 + version: 19.0.4(eslint-plugin-import@2.26.0)(eslint-plugin-jsx-a11y@6.6.1(eslint@8.23.0))(eslint-plugin-react-hooks@4.6.0(eslint@8.23.0))(eslint-plugin-react@7.31.6(eslint@8.23.0))(eslint@8.23.0) + eslint-config-airbnb-typescript: + specifier: ^17.1.0 + version: 17.1.0(@typescript-eslint/eslint-plugin@5.36.1(@typescript-eslint/parser@7.1.1(eslint@8.23.0)(typescript@5.4.2))(eslint@8.23.0)(typescript@5.4.2))(@typescript-eslint/parser@7.1.1(eslint@8.23.0)(typescript@5.4.2))(eslint-plugin-import@2.26.0)(eslint@8.23.0) + eslint-config-prettier: + specifier: ^8.5.0 + version: 8.5.0(eslint@8.23.0) + eslint-import-resolver-typescript: + specifier: ^3.5.0 + version: 3.5.0(eslint-plugin-import@2.26.0)(eslint@8.23.0) + eslint-plugin-import: + specifier: ^2.26.0 + version: 2.26.0(@typescript-eslint/parser@7.1.1(eslint@8.23.0)(typescript@5.4.2))(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0) + eslint-plugin-jsx-a11y: + specifier: ^6.6.1 + version: 6.6.1(eslint@8.23.0) + eslint-plugin-react: + specifier: ^7.31.6 + version: 7.31.6(eslint@8.23.0) + eslint-plugin-react-hooks: + specifier: ^4.6.0 + version: 4.6.0(eslint@8.23.0) + eslint-plugin-simple-import-sort: + specifier: ^8.0.0 + version: 8.0.0(eslint@8.23.0) + graphql: + specifier: 16.8.0 + version: 16.8.0 + husky: + specifier: ^8.0.1 + version: 8.0.1 + jsdom: + specifier: ^20.0.3 + version: 20.0.3 + lint-staged: + specifier: ^13.0.3 + version: 13.0.3(enquirer@2.3.6) + next: + specifier: ^12.3.0 + version: 12.3.0(@babel/core@7.20.12)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + node-mocks-http: + specifier: ^1.11.0 + version: 1.11.0 + prettier: + specifier: 2.7.1 + version: 2.7.1 + react: + specifier: ^18.2.0 + version: 18.2.0 + react-dom: + specifier: 18.2.0 + version: 18.2.0(react@18.2.0) + tsm: + specifier: ^2.2.2 + version: 2.2.2 + tsup: + specifier: ^6.2.3 + version: 6.2.3(postcss@8.4.21)(typescript@5.4.2) + typescript: + specifier: 5.4.2 + version: 5.4.2 + vi-fetch: + specifier: ^0.8.0 + version: 0.8.0 + vite: + specifier: ^4.0.4 + version: 4.0.5(@types/node@18.7.15) + vitest: + specifier: ^0.28.1 + version: 0.28.1(jsdom@20.0.3) + publishDirectory: dist packages: - /@ampproject/remapping@2.2.0: + '@ampproject/remapping@2.2.0': resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==} engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/gen-mapping': 0.1.1 - '@jridgewell/trace-mapping': 0.3.15 - dev: true - /@babel/code-frame@7.18.6: + '@babel/code-frame@7.18.6': resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/highlight': 7.18.6 - dev: true - /@babel/compat-data@7.20.10: + '@babel/compat-data@7.20.10': resolution: {integrity: sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==} engines: {node: '>=6.9.0'} - dev: true - /@babel/core@7.20.12: + '@babel/core@7.20.12': resolution: {integrity: sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==} engines: {node: '>=6.9.0'} - dependencies: - '@ampproject/remapping': 2.2.0 - '@babel/code-frame': 7.18.6 - '@babel/generator': 7.20.7 - '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.20.12) - '@babel/helper-module-transforms': 7.20.11 - '@babel/helpers': 7.20.7 - '@babel/parser': 7.20.7 - '@babel/template': 7.20.7 - '@babel/traverse': 7.20.12 - '@babel/types': 7.20.7 - convert-source-map: 1.8.0 - debug: 4.3.4 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.0 - transitivePeerDependencies: - - supports-color - dev: true - /@babel/generator@7.20.7: + '@babel/generator@7.20.7': resolution: {integrity: sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.20.7 - '@jridgewell/gen-mapping': 0.3.2 - jsesc: 2.5.2 - dev: true - /@babel/helper-compilation-targets@7.20.7(@babel/core@7.20.12): + '@babel/helper-compilation-targets@7.20.7': resolution: {integrity: sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - dependencies: - '@babel/compat-data': 7.20.10 - '@babel/core': 7.20.12 - '@babel/helper-validator-option': 7.18.6 - browserslist: 4.21.3 - lru-cache: 5.1.1 - semver: 6.3.0 - dev: true - /@babel/helper-environment-visitor@7.18.9: + '@babel/helper-environment-visitor@7.18.9': resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==} engines: {node: '>=6.9.0'} - dev: true - /@babel/helper-function-name@7.19.0: + '@babel/helper-function-name@7.19.0': resolution: {integrity: sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.20.7 - '@babel/types': 7.20.7 - dev: true - /@babel/helper-hoist-variables@7.18.6: + '@babel/helper-hoist-variables@7.18.6': resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.20.7 - dev: true - /@babel/helper-module-imports@7.18.6: + '@babel/helper-module-imports@7.18.6': resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.20.7 - dev: true - /@babel/helper-module-transforms@7.20.11: + '@babel/helper-module-transforms@7.20.11': resolution: {integrity: sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-module-imports': 7.18.6 - '@babel/helper-simple-access': 7.20.2 - '@babel/helper-split-export-declaration': 7.18.6 - '@babel/helper-validator-identifier': 7.19.1 - '@babel/template': 7.20.7 - '@babel/traverse': 7.20.12 - '@babel/types': 7.20.7 - transitivePeerDependencies: - - supports-color - dev: true - /@babel/helper-plugin-utils@7.18.9: + '@babel/helper-plugin-utils@7.18.9': resolution: {integrity: sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==} engines: {node: '>=6.9.0'} - dev: true - /@babel/helper-plugin-utils@7.20.2: + '@babel/helper-plugin-utils@7.20.2': resolution: {integrity: sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==} engines: {node: '>=6.9.0'} - dev: true - /@babel/helper-simple-access@7.20.2: + '@babel/helper-simple-access@7.20.2': resolution: {integrity: sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.20.7 - dev: true - /@babel/helper-split-export-declaration@7.18.6: + '@babel/helper-split-export-declaration@7.18.6': resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.20.7 - dev: true - /@babel/helper-string-parser@7.19.4: + '@babel/helper-string-parser@7.19.4': resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==} engines: {node: '>=6.9.0'} - dev: true - /@babel/helper-validator-identifier@7.18.6: + '@babel/helper-validator-identifier@7.18.6': resolution: {integrity: sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==} engines: {node: '>=6.9.0'} - dev: true - /@babel/helper-validator-identifier@7.19.1: + '@babel/helper-validator-identifier@7.19.1': resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} engines: {node: '>=6.9.0'} - dev: true - /@babel/helper-validator-option@7.18.6: + '@babel/helper-validator-option@7.18.6': resolution: {integrity: sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==} engines: {node: '>=6.9.0'} - dev: true - /@babel/helpers@7.20.7: + '@babel/helpers@7.20.7': resolution: {integrity: sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.20.7 - '@babel/traverse': 7.20.12 - '@babel/types': 7.20.7 - transitivePeerDependencies: - - supports-color - dev: true - /@babel/highlight@7.18.6: + '@babel/highlight@7.18.6': resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-validator-identifier': 7.18.6 - chalk: 2.4.2 - js-tokens: 4.0.0 - dev: true - /@babel/parser@7.20.7: + '@babel/parser@7.20.7': resolution: {integrity: sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==} engines: {node: '>=6.0.0'} hasBin: true - dependencies: - '@babel/types': 7.20.7 - dev: true - /@babel/plugin-transform-react-jsx-self@7.18.6(@babel/core@7.20.12): + '@babel/plugin-transform-react-jsx-self@7.18.6': resolution: {integrity: sha512-A0LQGx4+4Jv7u/tWzoJF7alZwnBDQd6cGLh9P+Ttk4dpiL+J5p7NSNv/9tlEFFJDq3kjxOavWmbm6t0Gk+A3Ig==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12 - '@babel/helper-plugin-utils': 7.18.9 - dev: true - /@babel/plugin-transform-react-jsx-source@7.19.6(@babel/core@7.20.12): + '@babel/plugin-transform-react-jsx-source@7.19.6': resolution: {integrity: sha512-RpAi004QyMNisst/pvSanoRdJ4q+jMCWyk9zdw/CyLB9j8RXEahodR6l2GyttDRyEVWZtbN+TpLiHJ3t34LbsQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12 - '@babel/helper-plugin-utils': 7.20.2 - dev: true - /@babel/runtime-corejs3@7.18.9: + '@babel/runtime-corejs3@7.18.9': resolution: {integrity: sha512-qZEWeccZCrHA2Au4/X05QW5CMdm4VjUDCrGq5gf1ZDcM4hRqreKrtwAn7yci9zfgAS9apvnsFXiGBHBAxZdK9A==} engines: {node: '>=6.9.0'} - dependencies: - core-js-pure: 3.25.0 - regenerator-runtime: 0.13.9 - dev: true - /@babel/runtime@7.18.9: + '@babel/runtime@7.18.9': resolution: {integrity: sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==} engines: {node: '>=6.9.0'} - dependencies: - regenerator-runtime: 0.13.9 - dev: true - /@babel/runtime@7.20.13: + '@babel/runtime@7.20.13': resolution: {integrity: sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==} engines: {node: '>=6.9.0'} - dependencies: - regenerator-runtime: 0.13.11 - dev: true - /@babel/template@7.20.7: + '@babel/template@7.20.7': resolution: {integrity: sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.18.6 - '@babel/parser': 7.20.7 - '@babel/types': 7.20.7 - dev: true - /@babel/traverse@7.20.12: + '@babel/traverse@7.20.12': resolution: {integrity: sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.18.6 - '@babel/generator': 7.20.7 - '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-function-name': 7.19.0 - '@babel/helper-hoist-variables': 7.18.6 - '@babel/helper-split-export-declaration': 7.18.6 - '@babel/parser': 7.20.7 - '@babel/types': 7.20.7 - debug: 4.3.4 - globals: 11.12.0 - transitivePeerDependencies: - - supports-color - dev: true - /@babel/types@7.20.7: + '@babel/types@7.20.7': resolution: {integrity: sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-string-parser': 7.19.4 - '@babel/helper-validator-identifier': 7.19.1 - to-fast-properties: 2.0.0 - dev: true - /@bcoe/v8-coverage@0.2.3: + '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} - dev: true - /@changesets/apply-release-plan@7.0.0: + '@changesets/apply-release-plan@7.0.0': resolution: {integrity: sha512-vfi69JR416qC9hWmFGSxj7N6wA5J222XNBmezSVATPWDVPIF7gkd4d8CpbEbXmRWbVrkoli3oerGS6dcL/BGsQ==} - dependencies: - '@babel/runtime': 7.20.13 - '@changesets/config': 3.0.0 - '@changesets/get-version-range-type': 0.4.0 - '@changesets/git': 3.0.0 - '@changesets/types': 6.0.0 - '@manypkg/get-packages': 1.1.3 - detect-indent: 6.1.0 - fs-extra: 7.0.1 - lodash.startcase: 4.4.0 - outdent: 0.5.0 - prettier: 2.7.1 - resolve-from: 5.0.0 - semver: 7.5.4 - dev: true - /@changesets/assemble-release-plan@6.0.0: + '@changesets/assemble-release-plan@6.0.0': resolution: {integrity: sha512-4QG7NuisAjisbW4hkLCmGW2lRYdPrKzro+fCtZaILX+3zdUELSvYjpL4GTv0E4aM9Mef3PuIQp89VmHJ4y2bfw==} - dependencies: - '@babel/runtime': 7.20.13 - '@changesets/errors': 0.2.0 - '@changesets/get-dependents-graph': 2.0.0 - '@changesets/types': 6.0.0 - '@manypkg/get-packages': 1.1.3 - semver: 7.5.4 - dev: true - /@changesets/changelog-git@0.2.0: + '@changesets/changelog-git@0.2.0': resolution: {integrity: sha512-bHOx97iFI4OClIT35Lok3sJAwM31VbUM++gnMBV16fdbtBhgYu4dxsphBF/0AZZsyAHMrnM0yFcj5gZM1py6uQ==} - dependencies: - '@changesets/types': 6.0.0 - dev: true - /@changesets/cli@2.27.1: + '@changesets/cli@2.27.1': resolution: {integrity: sha512-iJ91xlvRnnrJnELTp4eJJEOPjgpF3NOh4qeQehM6Ugiz9gJPRZ2t+TsXun6E3AMN4hScZKjqVXl0TX+C7AB3ZQ==} hasBin: true - dependencies: - '@babel/runtime': 7.20.13 - '@changesets/apply-release-plan': 7.0.0 - '@changesets/assemble-release-plan': 6.0.0 - '@changesets/changelog-git': 0.2.0 - '@changesets/config': 3.0.0 - '@changesets/errors': 0.2.0 - '@changesets/get-dependents-graph': 2.0.0 - '@changesets/get-release-plan': 4.0.0 - '@changesets/git': 3.0.0 - '@changesets/logger': 0.1.0 - '@changesets/pre': 2.0.0 - '@changesets/read': 0.6.0 - '@changesets/types': 6.0.0 - '@changesets/write': 0.3.0 - '@manypkg/get-packages': 1.1.3 - '@types/semver': 7.5.0 - ansi-colors: 4.1.3 - chalk: 2.4.2 - ci-info: 3.9.0 - enquirer: 2.3.6 - external-editor: 3.1.0 - fs-extra: 7.0.1 - human-id: 1.0.2 - meow: 6.1.1 - outdent: 0.5.0 - p-limit: 2.3.0 - preferred-pm: 3.0.3 - resolve-from: 5.0.0 - semver: 7.5.4 - spawndamnit: 2.0.0 - term-size: 2.2.1 - tty-table: 4.1.6 - dev: true - /@changesets/config@3.0.0: + '@changesets/config@3.0.0': resolution: {integrity: sha512-o/rwLNnAo/+j9Yvw9mkBQOZySDYyOr/q+wptRLcAVGlU6djOeP9v1nlalbL9MFsobuBVQbZCTp+dIzdq+CLQUA==} - dependencies: - '@changesets/errors': 0.2.0 - '@changesets/get-dependents-graph': 2.0.0 - '@changesets/logger': 0.1.0 - '@changesets/types': 6.0.0 - '@manypkg/get-packages': 1.1.3 - fs-extra: 7.0.1 - micromatch: 4.0.5 - dev: true - /@changesets/errors@0.2.0: + '@changesets/errors@0.2.0': resolution: {integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==} - dependencies: - extendable-error: 0.1.7 - dev: true - /@changesets/get-dependents-graph@2.0.0: + '@changesets/get-dependents-graph@2.0.0': resolution: {integrity: sha512-cafUXponivK4vBgZ3yLu944mTvam06XEn2IZGjjKc0antpenkYANXiiE6GExV/yKdsCnE8dXVZ25yGqLYZmScA==} - dependencies: - '@changesets/types': 6.0.0 - '@manypkg/get-packages': 1.1.3 - chalk: 2.4.2 - fs-extra: 7.0.1 - semver: 7.5.4 - dev: true - /@changesets/get-release-plan@4.0.0: + '@changesets/get-release-plan@4.0.0': resolution: {integrity: sha512-9L9xCUeD/Tb6L/oKmpm8nyzsOzhdNBBbt/ZNcjynbHC07WW4E1eX8NMGC5g5SbM5z/V+MOrYsJ4lRW41GCbg3w==} - dependencies: - '@babel/runtime': 7.20.13 - '@changesets/assemble-release-plan': 6.0.0 - '@changesets/config': 3.0.0 - '@changesets/pre': 2.0.0 - '@changesets/read': 0.6.0 - '@changesets/types': 6.0.0 - '@manypkg/get-packages': 1.1.3 - dev: true - /@changesets/get-version-range-type@0.4.0: + '@changesets/get-version-range-type@0.4.0': resolution: {integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==} - dev: true - /@changesets/git@3.0.0: + '@changesets/git@3.0.0': resolution: {integrity: sha512-vvhnZDHe2eiBNRFHEgMiGd2CT+164dfYyrJDhwwxTVD/OW0FUD6G7+4DIx1dNwkwjHyzisxGAU96q0sVNBns0w==} - dependencies: - '@babel/runtime': 7.20.13 - '@changesets/errors': 0.2.0 - '@changesets/types': 6.0.0 - '@manypkg/get-packages': 1.1.3 - is-subdir: 1.2.0 - micromatch: 4.0.5 - spawndamnit: 2.0.0 - dev: true - /@changesets/logger@0.1.0: + '@changesets/logger@0.1.0': resolution: {integrity: sha512-pBrJm4CQm9VqFVwWnSqKEfsS2ESnwqwH+xR7jETxIErZcfd1u2zBSqrHbRHR7xjhSgep9x2PSKFKY//FAshA3g==} - dependencies: - chalk: 2.4.2 - dev: true - /@changesets/parse@0.4.0: + '@changesets/parse@0.4.0': resolution: {integrity: sha512-TS/9KG2CdGXS27S+QxbZXgr8uPsP4yNJYb4BC2/NeFUj80Rni3TeD2qwWmabymxmrLo7JEsytXH1FbpKTbvivw==} - dependencies: - '@changesets/types': 6.0.0 - js-yaml: 3.14.1 - dev: true - /@changesets/pre@2.0.0: + '@changesets/pre@2.0.0': resolution: {integrity: sha512-HLTNYX/A4jZxc+Sq8D1AMBsv+1qD6rmmJtjsCJa/9MSRybdxh0mjbTvE6JYZQ/ZiQ0mMlDOlGPXTm9KLTU3jyw==} - dependencies: - '@babel/runtime': 7.20.13 - '@changesets/errors': 0.2.0 - '@changesets/types': 6.0.0 - '@manypkg/get-packages': 1.1.3 - fs-extra: 7.0.1 - dev: true - /@changesets/read@0.6.0: + '@changesets/read@0.6.0': resolution: {integrity: sha512-ZypqX8+/im1Fm98K4YcZtmLKgjs1kDQ5zHpc2U1qdtNBmZZfo/IBiG162RoP0CUF05tvp2y4IspH11PLnPxuuw==} - dependencies: - '@babel/runtime': 7.20.13 - '@changesets/git': 3.0.0 - '@changesets/logger': 0.1.0 - '@changesets/parse': 0.4.0 - '@changesets/types': 6.0.0 - chalk: 2.4.2 - fs-extra: 7.0.1 - p-filter: 2.1.0 - dev: true - /@changesets/types@4.1.0: + '@changesets/types@4.1.0': resolution: {integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==} - dev: true - /@changesets/types@6.0.0: + '@changesets/types@6.0.0': resolution: {integrity: sha512-b1UkfNulgKoWfqyHtzKS5fOZYSJO+77adgL7DLRDr+/7jhChN+QcHnbjiQVOz/U+Ts3PGNySq7diAItzDgugfQ==} - dev: true - /@changesets/write@0.3.0: + '@changesets/write@0.3.0': resolution: {integrity: sha512-slGLb21fxZVUYbyea+94uFiD6ntQW0M2hIKNznFizDhZPDgn2c/fv1UzzlW43RVzh1BEDuIqW6hzlJ1OflNmcw==} - dependencies: - '@babel/runtime': 7.20.13 - '@changesets/types': 6.0.0 - fs-extra: 7.0.1 - human-id: 1.0.2 - prettier: 2.7.1 - dev: true - /@esbuild/android-arm64@0.16.17: + '@esbuild/android-arm64@0.16.17': resolution: {integrity: sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==} engines: {node: '>=12'} cpu: [arm64] os: [android] - requiresBuild: true - dev: true - optional: true - /@esbuild/android-arm@0.16.17: + '@esbuild/android-arm@0.16.17': resolution: {integrity: sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==} engines: {node: '>=12'} cpu: [arm] os: [android] - requiresBuild: true - dev: true - optional: true - /@esbuild/android-x64@0.16.17: + '@esbuild/android-x64@0.16.17': resolution: {integrity: sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==} engines: {node: '>=12'} cpu: [x64] os: [android] - requiresBuild: true - dev: true - optional: true - /@esbuild/darwin-arm64@0.16.17: + '@esbuild/darwin-arm64@0.16.17': resolution: {integrity: sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] - requiresBuild: true - dev: true - optional: true - /@esbuild/darwin-x64@0.16.17: + '@esbuild/darwin-x64@0.16.17': resolution: {integrity: sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==} engines: {node: '>=12'} cpu: [x64] os: [darwin] - requiresBuild: true - dev: true - optional: true - /@esbuild/freebsd-arm64@0.16.17: + '@esbuild/freebsd-arm64@0.16.17': resolution: {integrity: sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/freebsd-x64@0.16.17: + '@esbuild/freebsd-x64@0.16.17': resolution: {integrity: sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-arm64@0.16.17: + '@esbuild/linux-arm64@0.16.17': resolution: {integrity: sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==} engines: {node: '>=12'} cpu: [arm64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-arm@0.16.17: + '@esbuild/linux-arm@0.16.17': resolution: {integrity: sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==} engines: {node: '>=12'} cpu: [arm] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-ia32@0.16.17: + '@esbuild/linux-ia32@0.16.17': resolution: {integrity: sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==} engines: {node: '>=12'} cpu: [ia32] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-loong64@0.14.54: + '@esbuild/linux-loong64@0.14.54': resolution: {integrity: sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==} engines: {node: '>=12'} cpu: [loong64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-loong64@0.15.7: + '@esbuild/linux-loong64@0.15.7': resolution: {integrity: sha512-IKznSJOsVUuyt7cDzzSZyqBEcZe+7WlBqTVXiF1OXP/4Nm387ToaXZ0fyLwI1iBlI/bzpxVq411QE2/Bt2XWWw==} engines: {node: '>=12'} cpu: [loong64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-loong64@0.16.17: + '@esbuild/linux-loong64@0.16.17': resolution: {integrity: sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==} engines: {node: '>=12'} cpu: [loong64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-mips64el@0.16.17: + '@esbuild/linux-mips64el@0.16.17': resolution: {integrity: sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-ppc64@0.16.17: + '@esbuild/linux-ppc64@0.16.17': resolution: {integrity: sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-riscv64@0.16.17: + '@esbuild/linux-riscv64@0.16.17': resolution: {integrity: sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-s390x@0.16.17: + '@esbuild/linux-s390x@0.16.17': resolution: {integrity: sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==} engines: {node: '>=12'} cpu: [s390x] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-x64@0.16.17: + '@esbuild/linux-x64@0.16.17': resolution: {integrity: sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==} engines: {node: '>=12'} cpu: [x64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/netbsd-x64@0.16.17: + '@esbuild/netbsd-x64@0.16.17': resolution: {integrity: sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/openbsd-x64@0.16.17: + '@esbuild/openbsd-x64@0.16.17': resolution: {integrity: sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/sunos-x64@0.16.17: + '@esbuild/sunos-x64@0.16.17': resolution: {integrity: sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==} engines: {node: '>=12'} cpu: [x64] os: [sunos] - requiresBuild: true - dev: true - optional: true - /@esbuild/win32-arm64@0.16.17: + '@esbuild/win32-arm64@0.16.17': resolution: {integrity: sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==} engines: {node: '>=12'} cpu: [arm64] os: [win32] - requiresBuild: true - dev: true - optional: true - /@esbuild/win32-ia32@0.16.17: + '@esbuild/win32-ia32@0.16.17': resolution: {integrity: sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==} engines: {node: '>=12'} cpu: [ia32] os: [win32] - requiresBuild: true - dev: true - optional: true - /@esbuild/win32-x64@0.16.17: + '@esbuild/win32-x64@0.16.17': resolution: {integrity: sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==} engines: {node: '>=12'} cpu: [x64] os: [win32] - requiresBuild: true - dev: true - optional: true - /@eslint/eslintrc@1.3.1: + '@eslint/eslintrc@1.3.1': resolution: {integrity: sha512-OhSY22oQQdw3zgPOOwdoj01l/Dzl1Z+xyUP33tkSN+aqyEhymJCcPHyXt+ylW8FSe0TfRC2VG+ROQOapD0aZSQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - ajv: 6.12.6 - debug: 4.3.4 - espree: 9.4.0 - globals: 13.17.0 - ignore: 5.2.0 - import-fresh: 3.3.0 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - dev: true - /@humanwhocodes/config-array@0.10.4: + '@humanwhocodes/config-array@0.10.4': resolution: {integrity: sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==} engines: {node: '>=10.10.0'} - dependencies: - '@humanwhocodes/object-schema': 1.2.1 - debug: 4.3.4 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - dev: true - /@humanwhocodes/gitignore-to-minimatch@1.0.2: + '@humanwhocodes/gitignore-to-minimatch@1.0.2': resolution: {integrity: sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==} - dev: true - /@humanwhocodes/module-importer@1.0.1: + '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} - dev: true - /@humanwhocodes/object-schema@1.2.1: + '@humanwhocodes/object-schema@1.2.1': resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} - dev: true - /@istanbuljs/schema@0.1.3: + '@istanbuljs/schema@0.1.3': resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} engines: {node: '>=8'} - dev: true - /@jridgewell/gen-mapping@0.1.1: + '@jridgewell/gen-mapping@0.1.1': resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==} engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.14 - dev: true - /@jridgewell/gen-mapping@0.3.2: + '@jridgewell/gen-mapping@0.3.2': resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==} engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.14 - '@jridgewell/trace-mapping': 0.3.15 - dev: true - /@jridgewell/resolve-uri@3.1.0: + '@jridgewell/resolve-uri@3.1.0': resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} engines: {node: '>=6.0.0'} - dev: true - /@jridgewell/set-array@1.1.2: + '@jridgewell/set-array@1.1.2': resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} engines: {node: '>=6.0.0'} - dev: true - /@jridgewell/sourcemap-codec@1.4.14: + '@jridgewell/sourcemap-codec@1.4.14': resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} - dev: true - /@jridgewell/trace-mapping@0.3.15: + '@jridgewell/trace-mapping@0.3.15': resolution: {integrity: sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==} - dependencies: - '@jridgewell/resolve-uri': 3.1.0 - '@jridgewell/sourcemap-codec': 1.4.14 - dev: true - /@manypkg/find-root@1.1.0: + '@manypkg/find-root@1.1.0': resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} - dependencies: - '@babel/runtime': 7.20.13 - '@types/node': 12.20.55 - find-up: 4.1.0 - fs-extra: 8.1.0 - dev: true - /@manypkg/get-packages@1.1.3: + '@manypkg/get-packages@1.1.3': resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} - dependencies: - '@babel/runtime': 7.20.13 - '@changesets/types': 4.1.0 - '@manypkg/find-root': 1.1.0 - fs-extra: 8.1.0 - globby: 11.1.0 - read-yaml-file: 1.1.0 - dev: true - /@next/env@12.3.0: + '@next/env@12.3.0': resolution: {integrity: sha512-PTJpjAFVbzBQ9xXpzMTroShvD5YDIIy46jQ7d4LrWpY+/5a8H90Tm8hE3Hvkc5RBRspVo7kvEOnqQms0A+2Q6w==} - dev: true - /@next/swc-android-arm-eabi@12.3.0: + '@next/swc-android-arm-eabi@12.3.0': resolution: {integrity: sha512-/PuirPnAKsYBw93w/7Q9hqy+KGOU9mjYprZ/faxMUJh/dc6v3rYLxkZKNG9nFPIW4QKNTCnhP40xF9hLnxO+xg==} engines: {node: '>= 10'} cpu: [arm] os: [android] - requiresBuild: true - dev: true - optional: true - /@next/swc-android-arm64@12.3.0: + '@next/swc-android-arm64@12.3.0': resolution: {integrity: sha512-OaI+FhAM6P9B6Ybwbn0Zl8YwWido0lLwhDBi9WiYCh4RQmIXAyVIoIJPHo4fP05+mXaJ/k1trvDvuURvHOq2qw==} engines: {node: '>= 10'} cpu: [arm64] os: [android] - requiresBuild: true - dev: true - optional: true - /@next/swc-darwin-arm64@12.3.0: + '@next/swc-darwin-arm64@12.3.0': resolution: {integrity: sha512-9s4d3Mhii+WFce8o8Jok7WC3Bawkr9wEUU++SJRptjU1L5tsfYJMrSYCACHLhZujziNDLyExe4Hwwsccps1sfg==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - requiresBuild: true - dev: true - optional: true - /@next/swc-darwin-x64@12.3.0: + '@next/swc-darwin-x64@12.3.0': resolution: {integrity: sha512-2scC4MqUTwGwok+wpVxP+zWp7WcCAVOtutki2E1n99rBOTnUOX6qXkgxSy083yBN6GqwuC/dzHeN7hIKjavfRA==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - requiresBuild: true - dev: true - optional: true - /@next/swc-freebsd-x64@12.3.0: + '@next/swc-freebsd-x64@12.3.0': resolution: {integrity: sha512-xAlruUREij/bFa+qsE1tmsP28t7vz02N4ZDHt2lh3uJUniE0Ne9idyIDLc1Ed0IF2RjfgOp4ZVunuS3OM0sngw==} engines: {node: '>= 10'} cpu: [x64] os: [freebsd] - requiresBuild: true - dev: true - optional: true - /@next/swc-linux-arm-gnueabihf@12.3.0: + '@next/swc-linux-arm-gnueabihf@12.3.0': resolution: {integrity: sha512-jin2S4VT/cugc2dSZEUIabhYDJNgrUh7fufbdsaAezgcQzqfdfJqfxl4E9GuafzB4cbRPTaqA0V5uqbp0IyGkQ==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - requiresBuild: true - dev: true - optional: true - /@next/swc-linux-arm64-gnu@12.3.0: + '@next/swc-linux-arm64-gnu@12.3.0': resolution: {integrity: sha512-RqJHDKe0WImeUrdR0kayTkRWgp4vD/MS7g0r6Xuf8+ellOFH7JAAJffDW3ayuVZeMYOa7RvgNFcOoWnrTUl9Nw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@next/swc-linux-arm64-musl@12.3.0: + '@next/swc-linux-arm64-musl@12.3.0': resolution: {integrity: sha512-nvNWoUieMjvDjpYJ/4SQe9lQs2xMj6ZRs8N+bmTrVu9leY2Fg3WD6W9p/1uU9hGO8u+OdF13wc4iRShu/WYIHg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@next/swc-linux-x64-gnu@12.3.0: + '@next/swc-linux-x64-gnu@12.3.0': resolution: {integrity: sha512-4ajhIuVU9PeQCMMhdDgZTLrHmjbOUFuIyg6J19hZqwEwDTSqQyrSLkbJs2Nd7IRiM6Ul/XyrtEFCpk4k+xD2+w==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@next/swc-linux-x64-musl@12.3.0: + '@next/swc-linux-x64-musl@12.3.0': resolution: {integrity: sha512-U092RBYbaGxoMAwpauePJEu2PuZSEoUCGJBvsptQr2/2XIMwAJDYM4c/M5NfYEsBr+yjvsYNsOpYfeQ88D82Yg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@next/swc-win32-arm64-msvc@12.3.0: + '@next/swc-win32-arm64-msvc@12.3.0': resolution: {integrity: sha512-pzSzaxjDEJe67bUok9Nxf9rykbJfHXW0owICFsPBsqHyc+cr8vpF7g9e2APTCddtVhvjkga9ILoZJ9NxWS7Yiw==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - requiresBuild: true - dev: true - optional: true - /@next/swc-win32-ia32-msvc@12.3.0: + '@next/swc-win32-ia32-msvc@12.3.0': resolution: {integrity: sha512-MQGUpMbYhQmTZ06a9e0hPQJnxFMwETo2WtyAotY3GEzbNCQVbCGhsvqEKcl+ZEHgShlHXUWvSffq1ZscY6gK7A==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] - requiresBuild: true - dev: true - optional: true - /@next/swc-win32-x64-msvc@12.3.0: + '@next/swc-win32-x64-msvc@12.3.0': resolution: {integrity: sha512-C/nw6OgQpEULWqs+wgMHXGvlJLguPRFFGqR2TAqWBerQ8J+Sg3z1ZTqwelkSi4FoqStGuZ2UdFHIDN1ySmR1xA==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - requiresBuild: true - dev: true - optional: true - /@nodelib/fs.scandir@2.1.5: + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - dev: true - /@nodelib/fs.stat@2.0.5: + '@nodelib/fs.stat@2.0.5': resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} engines: {node: '>= 8'} - dev: true - /@nodelib/fs.walk@1.2.8: + '@nodelib/fs.walk@1.2.8': resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.13.0 - dev: true - /@opentelemetry/api@1.7.0: + '@opentelemetry/api@1.7.0': resolution: {integrity: sha512-AdY5wvN0P2vXBi3b29hxZgSFvdhdxPB9+f0B6s//P9Q8nibRWeA3cHm8UmLpio9ABigkVHJ5NMPk+Mz8VCCyrw==} engines: {node: '>=8.0.0'} - dev: false - /@opentelemetry/semantic-conventions@1.18.1: + '@opentelemetry/semantic-conventions@1.18.1': resolution: {integrity: sha512-+NLGHr6VZwcgE/2lw8zDIufOCGnzsA5CbQIMleXZTrgkBd0TanCX+MiDYJ1TOS4KL/Tqk0nFRxawnaYr6pkZkA==} engines: {node: '>=14'} - dev: false - /@pkgr/utils@2.3.1: + '@pkgr/utils@2.3.1': resolution: {integrity: sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - dependencies: - cross-spawn: 7.0.3 - is-glob: 4.0.3 - open: 8.4.0 - picocolors: 1.0.0 - tiny-glob: 0.2.9 - tslib: 2.4.0 - dev: true - /@swc/helpers@0.4.11: + '@swc/helpers@0.4.11': resolution: {integrity: sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw==} - dependencies: - tslib: 2.4.0 - dev: true - /@testing-library/dom@8.17.1: + '@testing-library/dom@8.17.1': resolution: {integrity: sha512-KnH2MnJUzmFNPW6RIKfd+zf2Wue8mEKX0M3cpX6aKl5ZXrJM1/c/Pc8c2xDNYQCnJO48Sm5ITbMXgqTr3h4jxQ==} engines: {node: '>=12'} - dependencies: - '@babel/code-frame': 7.18.6 - '@babel/runtime': 7.18.9 - '@types/aria-query': 4.2.2 - aria-query: 5.0.2 - chalk: 4.1.2 - dom-accessibility-api: 0.5.14 - lz-string: 1.4.4 - pretty-format: 27.5.1 - dev: true - /@testing-library/react@13.4.0(react-dom@18.2.0)(react@18.2.0): + '@testing-library/react@13.4.0': resolution: {integrity: sha512-sXOGON+WNTh3MLE9rve97ftaZukN3oNf2KjDy7YTx6hcTO2uuLHuCGynMDhFwGw/jYf4OJ2Qk0i4i79qMNNkyw==} engines: {node: '>=12'} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - dependencies: - '@babel/runtime': 7.18.9 - '@testing-library/dom': 8.17.1 - '@types/react-dom': 18.0.6 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: true - /@tootallnate/once@2.0.0: + '@tootallnate/once@2.0.0': resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} - dev: true - /@types/aria-query@4.2.2: + '@types/aria-query@4.2.2': resolution: {integrity: sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==} - dev: true - /@types/aws-lambda@8.10.147: + '@types/aws-lambda@8.10.147': resolution: {integrity: sha512-nD0Z9fNIZcxYX5Mai2CTmFD7wX7UldCkW2ezCF8D1T5hdiLsnTWDGRpfRYntU6VjTdLQjOvyszru7I1c1oCQew==} - dev: true - /@types/chai-subset@1.3.3: + '@types/chai-subset@1.3.3': resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==} - dependencies: - '@types/chai': 4.3.4 - dev: true - /@types/chai@4.3.4: + '@types/chai@4.3.4': resolution: {integrity: sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==} - dev: true - /@types/debug@4.1.7: + '@types/debug@4.1.7': resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==} - dependencies: - '@types/ms': 0.7.31 - dev: true - /@types/istanbul-lib-coverage@2.0.4: + '@types/istanbul-lib-coverage@2.0.4': resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} - dev: true - /@types/json-schema@7.0.11: + '@types/json-schema@7.0.11': resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} - dev: true - /@types/json5@0.0.29: + '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - dev: true - /@types/minimist@1.2.2: + '@types/minimist@1.2.2': resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==} - dev: true - /@types/ms@0.7.31: + '@types/ms@0.7.31': resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} - dev: true - /@types/node@12.20.55: + '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - dev: true - /@types/node@18.7.15: + '@types/node@18.7.15': resolution: {integrity: sha512-XnjpaI8Bgc3eBag2Aw4t2Uj/49lLBSStHWfqKvIuXD7FIrZyMLWp8KuAFHAqxMZYTF9l08N1ctUn9YNybZJVmQ==} - dev: true - /@types/normalize-package-data@2.4.1: + '@types/normalize-package-data@2.4.1': resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} - dev: true - /@types/prop-types@15.7.5: + '@types/prop-types@15.7.5': resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} - dev: true - /@types/react-dom@18.0.6: + '@types/react-dom@18.0.6': resolution: {integrity: sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA==} - dependencies: - '@types/react': 18.0.21 - dev: true - /@types/react@18.0.21: + '@types/react@18.0.21': resolution: {integrity: sha512-7QUCOxvFgnD5Jk8ZKlUAhVcRj7GuJRjnjjiY/IUBWKgOlnvDvTMLD4RTF7NPyVmbRhNrbomZiOepg7M/2Kj1mA==} - dependencies: - '@types/prop-types': 15.7.5 - '@types/scheduler': 0.16.2 - csstype: 3.1.0 - dev: true - /@types/scheduler@0.16.2: + '@types/scheduler@0.16.2': resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==} - dev: true - /@types/semver@7.5.0: + '@types/semver@7.5.0': resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==} - dev: true - /@types/uuid@8.3.4: + '@types/uuid@8.3.4': resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==} - dev: true - /@typescript-eslint/eslint-plugin@5.36.1(@typescript-eslint/parser@7.1.1)(eslint@8.23.0)(typescript@5.4.2): + '@typescript-eslint/eslint-plugin@5.36.1': resolution: {integrity: sha512-iC40UK8q1tMepSDwiLbTbMXKDxzNy+4TfPWgIL661Ym0sD42vRcQU93IsZIrmi+x292DBr60UI/gSwfdVYexCA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -1219,24 +723,8 @@ packages: peerDependenciesMeta: typescript: optional: true - dependencies: - '@typescript-eslint/parser': 7.1.1(eslint@8.23.0)(typescript@5.4.2) - '@typescript-eslint/scope-manager': 5.36.1 - '@typescript-eslint/type-utils': 5.36.1(eslint@8.23.0)(typescript@5.4.2) - '@typescript-eslint/utils': 5.36.1(eslint@8.23.0)(typescript@5.4.2) - debug: 4.3.4 - eslint: 8.23.0 - functional-red-black-tree: 1.0.1 - ignore: 5.2.0 - regexpp: 3.2.0 - semver: 7.5.4 - tsutils: 3.21.0(typescript@5.4.2) - typescript: 5.4.2 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/parser@7.1.1(eslint@8.23.0)(typescript@5.4.2): + '@typescript-eslint/parser@7.1.1': resolution: {integrity: sha512-ZWUFyL0z04R1nAEgr9e79YtV5LbafdOtN7yapNbn1ansMyaegl2D4bL7vHoJ4HPSc4CaLwuCVas8CVuneKzplQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -1245,35 +733,16 @@ packages: peerDependenciesMeta: typescript: optional: true - dependencies: - '@typescript-eslint/scope-manager': 7.1.1 - '@typescript-eslint/types': 7.1.1 - '@typescript-eslint/typescript-estree': 7.1.1(typescript@5.4.2) - '@typescript-eslint/visitor-keys': 7.1.1 - debug: 4.3.4 - eslint: 8.23.0 - typescript: 5.4.2 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/scope-manager@5.36.1: + '@typescript-eslint/scope-manager@5.36.1': resolution: {integrity: sha512-pGC2SH3/tXdu9IH3ItoqciD3f3RRGCh7hb9zPdN2Drsr341zgd6VbhP5OHQO/reUqihNltfPpMpTNihFMarP2w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - '@typescript-eslint/types': 5.36.1 - '@typescript-eslint/visitor-keys': 5.36.1 - dev: true - /@typescript-eslint/scope-manager@7.1.1: + '@typescript-eslint/scope-manager@7.1.1': resolution: {integrity: sha512-cirZpA8bJMRb4WZ+rO6+mnOJrGFDd38WoXCEI57+CYBqta8Yc8aJym2i7vyqLL1vVYljgw0X27axkUXz32T8TA==} engines: {node: ^16.0.0 || >=18.0.0} - dependencies: - '@typescript-eslint/types': 7.1.1 - '@typescript-eslint/visitor-keys': 7.1.1 - dev: true - /@typescript-eslint/type-utils@5.36.1(eslint@8.23.0)(typescript@5.4.2): + '@typescript-eslint/type-utils@5.36.1': resolution: {integrity: sha512-xfZhfmoQT6m3lmlqDvDzv9TiCYdw22cdj06xY0obSznBsT///GK5IEZQdGliXpAOaRL34o8phEvXzEo/VJx13Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -1282,28 +751,16 @@ packages: peerDependenciesMeta: typescript: optional: true - dependencies: - '@typescript-eslint/typescript-estree': 5.36.1(typescript@5.4.2) - '@typescript-eslint/utils': 5.36.1(eslint@8.23.0)(typescript@5.4.2) - debug: 4.3.4 - eslint: 8.23.0 - tsutils: 3.21.0(typescript@5.4.2) - typescript: 5.4.2 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/types@5.36.1: + '@typescript-eslint/types@5.36.1': resolution: {integrity: sha512-jd93ShpsIk1KgBTx9E+hCSEuLCUFwi9V/urhjOWnOaksGZFbTOxAT47OH2d4NLJnLhkVD+wDbB48BuaycZPLBg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - /@typescript-eslint/types@7.1.1: + '@typescript-eslint/types@7.1.1': resolution: {integrity: sha512-KhewzrlRMrgeKm1U9bh2z5aoL4s7K3tK5DwHDn8MHv0yQfWFz/0ZR6trrIHHa5CsF83j/GgHqzdbzCXJ3crx0Q==} engines: {node: ^16.0.0 || >=18.0.0} - dev: true - /@typescript-eslint/typescript-estree@5.36.1(typescript@5.4.2): + '@typescript-eslint/typescript-estree@5.36.1': resolution: {integrity: sha512-ih7V52zvHdiX6WcPjsOdmADhYMDN15SylWRZrT2OMy80wzKbc79n8wFW0xpWpU0x3VpBz/oDgTm2xwDAnFTl+g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -1311,20 +768,8 @@ packages: peerDependenciesMeta: typescript: optional: true - dependencies: - '@typescript-eslint/types': 5.36.1 - '@typescript-eslint/visitor-keys': 5.36.1 - debug: 4.3.4 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.5.4 - tsutils: 3.21.0(typescript@5.4.2) - typescript: 5.4.2 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/typescript-estree@7.1.1(typescript@5.4.2): + '@typescript-eslint/typescript-estree@7.1.1': resolution: {integrity: sha512-9ZOncVSfr+sMXVxxca2OJOPagRwT0u/UHikM2Rd6L/aB+kL/QAuTnsv6MeXtjzCJYb8PzrXarypSGIPx3Jemxw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -1332,848 +777,448 @@ packages: peerDependenciesMeta: typescript: optional: true - dependencies: - '@typescript-eslint/types': 7.1.1 - '@typescript-eslint/visitor-keys': 7.1.1 - debug: 4.3.4 - globby: 11.1.0 - is-glob: 4.0.3 - minimatch: 9.0.3 - semver: 7.6.0 - ts-api-utils: 1.2.1(typescript@5.4.2) - typescript: 5.4.2 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/utils@5.36.1(eslint@8.23.0)(typescript@5.4.2): + '@typescript-eslint/utils@5.36.1': resolution: {integrity: sha512-lNj4FtTiXm5c+u0pUehozaUWhh7UYKnwryku0nxJlYUEWetyG92uw2pr+2Iy4M/u0ONMKzfrx7AsGBTCzORmIg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - dependencies: - '@types/json-schema': 7.0.11 - '@typescript-eslint/scope-manager': 5.36.1 - '@typescript-eslint/types': 5.36.1 - '@typescript-eslint/typescript-estree': 5.36.1(typescript@5.4.2) - eslint: 8.23.0 - eslint-scope: 5.1.1 - eslint-utils: 3.0.0(eslint@8.23.0) - transitivePeerDependencies: - - supports-color - - typescript - dev: true - /@typescript-eslint/visitor-keys@5.36.1: + '@typescript-eslint/visitor-keys@5.36.1': resolution: {integrity: sha512-ojB9aRyRFzVMN3b5joSYni6FAS10BBSCAfKJhjJAV08t/a95aM6tAhz+O1jF+EtgxktuSO3wJysp2R+Def/IWQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - '@typescript-eslint/types': 5.36.1 - eslint-visitor-keys: 3.3.0 - dev: true - /@typescript-eslint/visitor-keys@7.1.1: + '@typescript-eslint/visitor-keys@7.1.1': resolution: {integrity: sha512-yTdHDQxY7cSoCcAtiBzVzxleJhkGB9NncSIyMYe2+OGON1ZsP9zOPws/Pqgopa65jvknOjlk/w7ulPlZ78PiLQ==} engines: {node: ^16.0.0 || >=18.0.0} - dependencies: - '@typescript-eslint/types': 7.1.1 - eslint-visitor-keys: 3.4.3 - dev: true - /@upstash/redis@1.24.3: + '@upstash/redis@1.24.3': resolution: {integrity: sha512-gw6d4IA1biB4eye5ESaXc0zOlVQI94aptsBvVcTghYWu1kRmOrJFoMFEDCa8p5uzluyYAOFCuY2GWLR6O4ZoIw==} - dependencies: - crypto-js: 4.2.0 - dev: true - /@vercel/kv@1.0.0: + '@vercel/kv@1.0.0': resolution: {integrity: sha512-StouXunmEqUfKE+1joSYfELWEEnI1MhTnzUdarHtv6H18RAm3cf5u5g9ElvA1DJNHcrMT6g5yVAhZcYRbk6lvg==} engines: {node: '>=14.6'} - dependencies: - '@upstash/redis': 1.24.3 - dev: true - /@vitejs/plugin-react@3.0.1(vite@4.0.5): + '@vitejs/plugin-react@3.0.1': resolution: {integrity: sha512-mx+QvYwIbbpOIJw+hypjnW1lAbKDHtWK5ibkF/V1/oMBu8HU/chb+SnqJDAsLq1+7rGqjktCEomMTM5KShzUKQ==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: vite: ^4.0.0 - dependencies: - '@babel/core': 7.20.12 - '@babel/plugin-transform-react-jsx-self': 7.18.6(@babel/core@7.20.12) - '@babel/plugin-transform-react-jsx-source': 7.19.6(@babel/core@7.20.12) - magic-string: 0.27.0 - react-refresh: 0.14.0 - vite: 4.0.5(@types/node@18.7.15) - transitivePeerDependencies: - - supports-color - dev: true - /@vitest/coverage-c8@0.27.2(jsdom@20.0.3): + '@vitest/coverage-c8@0.27.2': resolution: {integrity: sha512-1MFwlwfwIfPFLfu6aN+dZ5jo2aOah5nAwoq/SrqUkt9rXzUmohLOgI1GTT0PpXbJKqaZicIlWuBjiC+BjVgRwQ==} - dependencies: - c8: 7.12.0 - vitest: 0.27.2(jsdom@20.0.3) - transitivePeerDependencies: - - '@edge-runtime/vm' - - '@vitest/browser' - - '@vitest/ui' - - happy-dom - - jsdom - - less - - sass - - stylus - - sugarss - - supports-color - - terser - dev: true - /@vitest/expect@0.28.1: + '@vitest/expect@0.28.1': resolution: {integrity: sha512-BOvWjBoocKrrTTTC0opIvzOEa7WR/Ovx4++QYlbjYKjnQJfWRSEQkTpAIEfOURtZ/ICcaLk5jvsRshXvjarZew==} - dependencies: - '@vitest/spy': 0.28.1 - '@vitest/utils': 0.28.1 - chai: 4.3.7 - dev: true - /@vitest/runner@0.28.1: + '@vitest/runner@0.28.1': resolution: {integrity: sha512-kOdmgiNe+mAxZhvj2eUTqKnjfvzzknmrcS+SZXV7j6VgJuWPFAMCv3TWOe03nF9dkqDfVLCDRw/hwFuCzmzlQg==} - dependencies: - '@vitest/utils': 0.28.1 - p-limit: 4.0.0 - pathe: 1.1.0 - dev: true - /@vitest/spy@0.28.1: + '@vitest/spy@0.28.1': resolution: {integrity: sha512-XGlD78cG3IxXNnGwEF121l0MfTNlHSdI25gS2ik0z6f/D9wWUOru849QkJbuNl4CMlZCtNkx3b5IS6MRwKGKuA==} - dependencies: - tinyspy: 1.0.2 - dev: true - /@vitest/utils@0.28.1: + '@vitest/utils@0.28.1': resolution: {integrity: sha512-a7cV1fs5MeU+W+8sn8gM9gV+q7V/wYz3/4y016w/icyJEKm9AMdSHnrzxTWaElJ07X40pwU6m5353Jlw6Rbd8w==} - dependencies: - cli-truncate: 3.1.0 - diff: 5.1.0 - loupe: 2.3.6 - picocolors: 1.0.0 - pretty-format: 27.5.1 - dev: true - /abab@2.0.6: + abab@2.0.6: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} - dev: true - /accepts@1.3.8: + accepts@1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} - dependencies: - mime-types: 2.1.35 - negotiator: 0.6.3 - dev: true - /acorn-globals@7.0.1: + acorn-globals@7.0.1: resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==} - dependencies: - acorn: 8.8.1 - acorn-walk: 8.2.0 - dev: true - /acorn-jsx@5.3.2(acorn@8.8.1): + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - dependencies: - acorn: 8.8.1 - dev: true - /acorn-walk@8.2.0: + acorn-walk@8.2.0: resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} engines: {node: '>=0.4.0'} - dev: true - /acorn@8.8.1: + acorn@8.8.1: resolution: {integrity: sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==} engines: {node: '>=0.4.0'} hasBin: true - dev: true - /agent-base@6.0.2: + agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} - dependencies: - debug: 4.3.4 - transitivePeerDependencies: - - supports-color - dev: true - /aggregate-error@3.1.0: + aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} - dependencies: - clean-stack: 2.2.0 - indent-string: 4.0.0 - dev: true - /ajv@6.12.6: + ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - dev: true - /ansi-colors@4.1.3: + ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} - dev: true - /ansi-escapes@4.3.2: + ansi-escapes@4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} - dependencies: - type-fest: 0.21.3 - dev: true - /ansi-regex@5.0.1: + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - dev: true - /ansi-regex@6.0.1: + ansi-regex@6.0.1: resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} engines: {node: '>=12'} - dev: true - /ansi-styles@3.2.1: + ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} - dependencies: - color-convert: 1.9.3 - dev: true - /ansi-styles@4.3.0: + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} - dependencies: - color-convert: 2.0.1 - dev: true - /ansi-styles@5.2.0: + ansi-styles@5.2.0: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} - dev: true - /ansi-styles@6.1.0: + ansi-styles@6.1.0: resolution: {integrity: sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==} engines: {node: '>=12'} - dev: true - /any-promise@1.3.0: + any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - dev: true - /anymatch@3.1.2: + anymatch@3.1.2: resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==} engines: {node: '>= 8'} - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 - dev: true - /argparse@1.0.10: + argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - dependencies: - sprintf-js: 1.0.3 - dev: true - /argparse@2.0.1: + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - dev: true - /aria-query@4.2.2: + aria-query@4.2.2: resolution: {integrity: sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==} engines: {node: '>=6.0'} - dependencies: - '@babel/runtime': 7.18.9 - '@babel/runtime-corejs3': 7.18.9 - dev: true - /aria-query@5.0.2: + aria-query@5.0.2: resolution: {integrity: sha512-eigU3vhqSO+Z8BKDnVLN/ompjhf3pYzecKXz8+whRy+9gZu8n1TCGfwzQUUPnqdHl9ax1Hr9031orZ+UOEYr7Q==} engines: {node: '>=6.0'} - dev: true - /array-includes@3.1.5: + array-includes@3.1.5: resolution: {integrity: sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.2 - get-intrinsic: 1.1.2 - is-string: 1.0.7 - dev: true - /array-union@2.1.0: + array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} - dev: true - /array.prototype.flat@1.3.0: + array.prototype.flat@1.3.0: resolution: {integrity: sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.2 - es-shim-unscopables: 1.0.0 - dev: true - /array.prototype.flatmap@1.3.0: + array.prototype.flatmap@1.3.0: resolution: {integrity: sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.2 - es-shim-unscopables: 1.0.0 - dev: true - /arrify@1.0.1: + arrify@1.0.1: resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} engines: {node: '>=0.10.0'} - dev: true - /assertion-error@1.1.0: + assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} - dev: true - /ast-types-flow@0.0.7: + ast-types-flow@0.0.7: resolution: {integrity: sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==} - dev: true - /astral-regex@2.0.0: + astral-regex@2.0.0: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} engines: {node: '>=8'} - dev: true - /asynckit@0.4.0: + asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - dev: true - /available-typed-arrays@1.0.7: + available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - dependencies: - possible-typed-array-names: 1.0.0 - dev: true - /aws-lambda@1.0.7: + aws-lambda@1.0.7: resolution: {integrity: sha512-9GNFMRrEMG5y3Jvv+V4azWvc+qNWdWLTjDdhf/zgMlz8haaaLWv0xeAIWxz9PuWUBawsVxy0zZotjCdR3Xq+2w==} hasBin: true - dependencies: - aws-sdk: 2.1692.0 - commander: 3.0.2 - js-yaml: 3.14.1 - watchpack: 2.4.2 - dev: true - /aws-sdk@2.1692.0: + aws-sdk@2.1692.0: resolution: {integrity: sha512-x511uiJ/57FIsbgUe5csJ13k3uzu25uWQE+XqfBis/sB0SFoiElJWXRkgEAUh0U6n40eT3ay5Ue4oPkRMu1LYw==} engines: {node: '>= 10.0.0'} - requiresBuild: true - dependencies: - buffer: 4.9.2 - events: 1.1.1 - ieee754: 1.1.13 - jmespath: 0.16.0 - querystring: 0.2.0 - sax: 1.2.1 - url: 0.10.3 - util: 0.12.5 - uuid: 8.0.0 - xml2js: 0.6.2 - dev: true - /axe-core@4.4.3: + axe-core@4.4.3: resolution: {integrity: sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==} engines: {node: '>=4'} - dev: true - /axobject-query@2.2.0: + axobject-query@2.2.0: resolution: {integrity: sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==} - dev: true - /balanced-match@1.0.2: + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true - /base64-js@1.5.1: + base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - dev: true - /better-path-resolve@1.0.0: + better-path-resolve@1.0.0: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} - dependencies: - is-windows: 1.0.2 - dev: true - /binary-extensions@2.2.0: + binary-extensions@2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} - dev: true - /brace-expansion@1.1.11: + brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - dev: true - /brace-expansion@2.0.1: + brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - dependencies: - balanced-match: 1.0.2 - dev: true - /braces@3.0.2: + braces@3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} engines: {node: '>=8'} - dependencies: - fill-range: 7.0.1 - dev: true - /breakword@1.0.5: + breakword@1.0.5: resolution: {integrity: sha512-ex5W9DoOQ/LUEU3PMdLs9ua/CYZl1678NUkKOdUSi8Aw5F1idieaiRURCBFJCwVcrD1J8Iy3vfWSloaMwO2qFg==} - dependencies: - wcwidth: 1.0.1 - dev: true - /browserslist@4.21.3: + browserslist@4.21.3: resolution: {integrity: sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true - dependencies: - caniuse-lite: 1.0.30001390 - electron-to-chromium: 1.4.241 - node-releases: 2.0.6 - update-browserslist-db: 1.0.7(browserslist@4.21.3) - dev: true - /buffer-from@1.1.2: + buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - dev: true - /buffer@4.9.2: + buffer@4.9.2: resolution: {integrity: sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==} - dependencies: - base64-js: 1.5.1 - ieee754: 1.1.13 - isarray: 1.0.0 - dev: true - /bundle-require@3.1.0(esbuild@0.15.7): + bundle-require@3.1.0: resolution: {integrity: sha512-IIXtAO7fKcwPHNPt9kY/WNVJqy7NDy6YqJvv6ENH0TOZoJ+yjpEsn1w40WKZbR2ibfu5g1rfgJTvmFHpm5aOMA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} peerDependencies: esbuild: '>=0.13' - dependencies: - esbuild: 0.15.7 - load-tsconfig: 0.2.3 - dev: true - /busboy@1.6.0: + busboy@1.6.0: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} - dependencies: - streamsearch: 1.1.0 - dev: false - /bytes@3.1.2: + bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} - dev: false - /c8@7.12.0: + c8@7.12.0: resolution: {integrity: sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A==} engines: {node: '>=10.12.0'} hasBin: true - dependencies: - '@bcoe/v8-coverage': 0.2.3 - '@istanbuljs/schema': 0.1.3 - find-up: 5.0.0 - foreground-child: 2.0.0 - istanbul-lib-coverage: 3.2.0 - istanbul-lib-report: 3.0.0 - istanbul-reports: 3.1.5 - rimraf: 3.0.2 - test-exclude: 6.0.0 - v8-to-istanbul: 9.0.1 - yargs: 16.2.0 - yargs-parser: 20.2.9 - dev: true - /cac@6.7.14: + cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} - dev: true - /call-bind-apply-helpers@1.0.1: + call-bind-apply-helpers@1.0.1: resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==} engines: {node: '>= 0.4'} - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - dev: true - /call-bind@1.0.2: + call-bind@1.0.2: resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} - dependencies: - function-bind: 1.1.1 - get-intrinsic: 1.1.2 - dev: true - /call-bind@1.0.8: + call-bind@1.0.8: resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} engines: {node: '>= 0.4'} - dependencies: - call-bind-apply-helpers: 1.0.1 - es-define-property: 1.0.1 - get-intrinsic: 1.2.7 - set-function-length: 1.2.2 - dev: true - /call-bound@1.0.3: + call-bound@1.0.3: resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==} engines: {node: '>= 0.4'} - dependencies: - call-bind-apply-helpers: 1.0.1 - get-intrinsic: 1.2.7 - dev: true - /callsites@3.1.0: + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - dev: true - /camelcase-keys@6.2.2: + camelcase-keys@6.2.2: resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==} engines: {node: '>=8'} - dependencies: - camelcase: 5.3.1 - map-obj: 4.3.0 - quick-lru: 4.0.1 - dev: true - /camelcase@5.3.1: + camelcase@5.3.1: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} - dev: true - /caniuse-lite@1.0.30001390: + caniuse-lite@1.0.30001390: resolution: {integrity: sha512-sS4CaUM+/+vqQUlCvCJ2WtDlV81aWtHhqeEVkLokVJJa3ViN4zDxAGfq9R8i1m90uGHxo99cy10Od+lvn3hf0g==} - dev: true - /chai@4.3.7: + chai@4.3.7: resolution: {integrity: sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==} engines: {node: '>=4'} - dependencies: - assertion-error: 1.1.0 - check-error: 1.0.2 - deep-eql: 4.1.3 - get-func-name: 2.0.0 - loupe: 2.3.4 - pathval: 1.1.1 - type-detect: 4.0.8 - dev: true - /chalk@2.4.2: + chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 - dev: true - /chalk@4.1.2: + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - dev: true - /chardet@0.7.0: + chardet@0.7.0: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} - dev: true - /check-error@1.0.2: + check-error@1.0.2: resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==} - dev: true - /chokidar@3.5.3: + chokidar@3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} - dependencies: - anymatch: 3.1.2 - braces: 3.0.2 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - dev: true - /ci-info@3.9.0: + ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} - dev: true - /clean-publish@4.0.1: + clean-publish@4.0.1: resolution: {integrity: sha512-6v0bh5kQD5FDlxBgXDVNNc6KmAB7iIP/GHD91q9xsGVZT5XB9Y8TNqB7dL5u9PTZlBeLpBw+A1AseRlEEJLSWA==} engines: {node: '>= 16.0.0'} hasBin: true - dependencies: - cross-spawn: 7.0.3 - fast-glob: 3.2.11 - lilconfig: 2.0.6 - micromatch: 4.0.5 - dev: true - /clean-stack@2.2.0: + clean-stack@2.2.0: resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} engines: {node: '>=6'} - dev: true - /cli-cursor@3.1.0: + cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} - dependencies: - restore-cursor: 3.1.0 - dev: true - /cli-truncate@2.1.0: + cli-truncate@2.1.0: resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} engines: {node: '>=8'} - dependencies: - slice-ansi: 3.0.0 - string-width: 4.2.3 - dev: true - /cli-truncate@3.1.0: + cli-truncate@3.1.0: resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - slice-ansi: 5.0.0 - string-width: 5.1.2 - dev: true - /cliui@6.0.0: + cliui@6.0.0: resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 6.2.0 - dev: true - /cliui@7.0.4: + cliui@7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - dev: true - /cliui@8.0.1: + cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - dev: true - /clone@1.0.4: + clone@1.0.4: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} - dev: true - /color-convert@1.9.3: + color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} - dependencies: - color-name: 1.1.3 - dev: true - /color-convert@2.0.1: + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} - dependencies: - color-name: 1.1.4 - dev: true - /color-name@1.1.3: + color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - dev: true - /color-name@1.1.4: + color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true - /colorette@2.0.19: + colorette@2.0.19: resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==} - dev: true - /combined-stream@1.0.8: + combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} - dependencies: - delayed-stream: 1.0.0 - dev: true - /commander@3.0.2: + commander@3.0.2: resolution: {integrity: sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==} - dev: true - /commander@4.1.1: + commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} - dev: true - /commander@9.4.1: + commander@9.4.1: resolution: {integrity: sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==} engines: {node: ^12.20.0 || >=14} - dev: true - /concat-map@0.0.1: + concat-map@0.0.1: resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} - dev: true - /confusing-browser-globals@1.0.11: + confusing-browser-globals@1.0.11: resolution: {integrity: sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==} - dev: true - /content-disposition@0.5.4: + content-disposition@0.5.4: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} - dependencies: - safe-buffer: 5.2.1 - dev: true - /convert-source-map@1.8.0: + convert-source-map@1.8.0: resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==} - dependencies: - safe-buffer: 5.1.2 - dev: true - /core-js-pure@3.25.0: + core-js-pure@3.25.0: resolution: {integrity: sha512-IeHpLwk3uoci37yoI2Laty59+YqH9x5uR65/yiA0ARAJrTrN4YU0rmauLWfvqOuk77SlNJXj2rM6oT/dBD87+A==} - requiresBuild: true - dev: true - /cross-spawn@5.1.0: + cross-spawn@5.1.0: resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==} - dependencies: - lru-cache: 4.1.5 - shebang-command: 1.2.0 - which: 1.3.1 - dev: true - /cross-spawn@7.0.3: + cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - dev: true - /crypto-js@4.2.0: + crypto-js@4.2.0: resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} - dev: true - /cssom@0.3.8: + cssom@0.3.8: resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==} - dev: true - /cssom@0.5.0: + cssom@0.5.0: resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==} - dev: true - /cssstyle@2.3.0: + cssstyle@2.3.0: resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==} engines: {node: '>=8'} - dependencies: - cssom: 0.3.8 - dev: true - /csstype@3.1.0: + csstype@3.1.0: resolution: {integrity: sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==} - dev: true - /csv-generate@3.4.3: + csv-generate@3.4.3: resolution: {integrity: sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==} - dev: true - /csv-parse@4.16.3: + csv-parse@4.16.3: resolution: {integrity: sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==} - dev: true - /csv-stringify@5.6.5: + csv-stringify@5.6.5: resolution: {integrity: sha512-PjiQ659aQ+fUTQqSrd1XEDnOr52jh30RBurfzkscaE2tPaFsDH5wOAHJiw8XAHphRknCwMUE9KRayc4K/NbO8A==} - dev: true - /csv@5.5.3: + csv@5.5.3: resolution: {integrity: sha512-QTaY0XjjhTQOdguARF0lGKm5/mEq9PD9/VhZZegHDIBq2tQwgNpHc3dneD4mGo2iJs+fTKv5Bp0fZ+BRuY3Z0g==} engines: {node: '>= 0.1.90'} - dependencies: - csv-generate: 3.4.3 - csv-parse: 4.16.3 - csv-stringify: 5.6.5 - stream-transform: 2.1.3 - dev: true - /damerau-levenshtein@1.0.8: + damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} - dev: true - /data-urls@3.0.2: + data-urls@3.0.2: resolution: {integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==} engines: {node: '>=12'} - dependencies: - abab: 2.0.6 - whatwg-mimetype: 3.0.0 - whatwg-url: 11.0.0 - dev: true - /debug@2.6.9: + debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: supports-color: '*' peerDependenciesMeta: supports-color: optional: true - dependencies: - ms: 2.0.0 - dev: true - /debug@3.2.7: + debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: supports-color: '*' peerDependenciesMeta: supports-color: optional: true - dependencies: - ms: 2.1.3 - dev: true - /debug@4.3.4: + debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} peerDependencies: @@ -2181,604 +1226,3876 @@ packages: peerDependenciesMeta: supports-color: optional: true - dependencies: - ms: 2.1.2 - /decamelize-keys@1.1.1: + decamelize-keys@1.1.1: resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} engines: {node: '>=0.10.0'} - dependencies: - decamelize: 1.2.0 - map-obj: 1.0.1 - dev: true - /decamelize@1.2.0: + decamelize@1.2.0: resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} engines: {node: '>=0.10.0'} - dev: true - /decimal.js@10.4.3: + decimal.js@10.4.3: resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} - dev: true - /decode-uri-component@0.2.2: + decode-uri-component@0.2.2: resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} engines: {node: '>=0.10'} - dev: true - /deep-eql@4.1.3: + deep-eql@4.1.3: resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} engines: {node: '>=6'} - dependencies: - type-detect: 4.0.8 - dev: true - /deep-is@0.1.4: + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - dev: true - /defaults@1.0.3: + defaults@1.0.3: resolution: {integrity: sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==} - dependencies: - clone: 1.0.4 - dev: true - /define-data-property@1.1.4: + define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} - dependencies: - es-define-property: 1.0.1 - es-errors: 1.3.0 - gopd: 1.2.0 - dev: true - /define-lazy-prop@2.0.0: + define-lazy-prop@2.0.0: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} engines: {node: '>=8'} - dev: true - /define-properties@1.1.4: + define-properties@1.1.4: resolution: {integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==} engines: {node: '>= 0.4'} - dependencies: - has-property-descriptors: 1.0.0 - object-keys: 1.1.1 - dev: true - /delayed-stream@1.0.0: + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} - dev: true - /depd@1.1.2: + depd@1.1.2: resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} engines: {node: '>= 0.6'} - dev: true - /depd@2.0.0: + depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} - dev: false - /detect-indent@6.1.0: + detect-indent@6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} - dev: true - /diff@5.1.0: + diff@5.1.0: resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==} engines: {node: '>=0.3.1'} - dev: true - /dir-glob@3.0.1: + dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} - dependencies: - path-type: 4.0.0 - dev: true - /doctrine@2.1.0: + doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} - dependencies: - esutils: 2.0.3 - dev: true - /doctrine@3.0.0: + doctrine@3.0.0: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} - dependencies: - esutils: 2.0.3 - dev: true - /dom-accessibility-api@0.5.14: + dom-accessibility-api@0.5.14: resolution: {integrity: sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg==} - dev: true - /domexception@4.0.0: + domexception@4.0.0: resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==} engines: {node: '>=12'} - dependencies: - webidl-conversions: 7.0.0 - dev: true - /dunder-proto@1.0.1: + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} - dependencies: - call-bind-apply-helpers: 1.0.1 - es-errors: 1.3.0 - gopd: 1.2.0 - dev: true - /eastasianwidth@0.2.0: + eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - dev: true - /electron-to-chromium@1.4.241: + electron-to-chromium@1.4.241: resolution: {integrity: sha512-e7Wsh4ilaioBZ5bMm6+F4V5c11dh56/5Jwz7Hl5Tu1J7cnB+Pqx5qIF2iC7HPpfyQMqGSvvLP5bBAIDd2gAtGw==} - dev: true - /emoji-regex@8.0.0: + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: true - /emoji-regex@9.2.2: + emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - dev: true - /enhanced-resolve@5.10.0: + enhanced-resolve@5.10.0: resolution: {integrity: sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==} engines: {node: '>=10.13.0'} - dependencies: - graceful-fs: 4.2.10 - tapable: 2.2.1 - dev: true - /enquirer@2.3.6: + enquirer@2.3.6: resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==} engines: {node: '>=8.6'} - dependencies: - ansi-colors: 4.1.3 - dev: true - /entities@4.4.0: + entities@4.4.0: resolution: {integrity: sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==} engines: {node: '>=0.12'} - dev: true - /error-ex@1.3.2: + error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - dependencies: - is-arrayish: 0.2.1 - dev: true - /es-abstract@1.20.2: + es-abstract@1.20.2: resolution: {integrity: sha512-XxXQuVNrySBNlEkTYJoDNFe5+s2yIOpzq80sUHEdPdQr0S5nTLz4ZPPPswNIpKseDDUS5yghX1gfLIHQZ1iNuQ==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - es-to-primitive: 1.2.1 - function-bind: 1.1.1 - function.prototype.name: 1.1.5 - get-intrinsic: 1.1.2 - get-symbol-description: 1.0.0 - has: 1.0.3 - has-property-descriptors: 1.0.0 - has-symbols: 1.0.3 - internal-slot: 1.0.3 - is-callable: 1.2.4 - is-negative-zero: 2.0.2 - is-regex: 1.1.4 - is-shared-array-buffer: 1.0.2 - is-string: 1.0.7 - is-weakref: 1.0.2 - object-inspect: 1.12.2 - object-keys: 1.1.1 - object.assign: 4.1.4 - regexp.prototype.flags: 1.4.3 - string.prototype.trimend: 1.0.5 - string.prototype.trimstart: 1.0.5 - unbox-primitive: 1.0.2 - dev: true - /es-define-property@1.0.1: + es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} - dev: true - /es-errors@1.3.0: + es-errors@1.3.0: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - dev: true - /es-object-atoms@1.1.1: + es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} - dependencies: - es-errors: 1.3.0 - dev: true - /es-shim-unscopables@1.0.0: + es-shim-unscopables@1.0.0: resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} - dependencies: - has: 1.0.3 - dev: true - /es-to-primitive@1.2.1: + es-to-primitive@1.2.1: resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} engines: {node: '>= 0.4'} - dependencies: - is-callable: 1.2.4 - is-date-object: 1.0.5 - is-symbol: 1.0.4 - dev: true - /esbuild-android-64@0.14.54: + esbuild-android-64@0.14.54: resolution: {integrity: sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==} engines: {node: '>=12'} cpu: [x64] os: [android] - requiresBuild: true - dev: true - optional: true - /esbuild-android-64@0.15.7: + esbuild-android-64@0.15.7: resolution: {integrity: sha512-p7rCvdsldhxQr3YHxptf1Jcd86dlhvc3EQmQJaZzzuAxefO9PvcI0GLOa5nCWem1AJ8iMRu9w0r5TG8pHmbi9w==} engines: {node: '>=12'} cpu: [x64] os: [android] - requiresBuild: true - dev: true - optional: true - /esbuild-android-arm64@0.14.54: + esbuild-android-arm64@0.14.54: resolution: {integrity: sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==} engines: {node: '>=12'} cpu: [arm64] os: [android] - requiresBuild: true - dev: true - optional: true - /esbuild-android-arm64@0.15.7: + esbuild-android-arm64@0.15.7: resolution: {integrity: sha512-L775l9ynJT7rVqRM5vo+9w5g2ysbOCfsdLV4CWanTZ1k/9Jb3IYlQ06VCI1edhcosTYJRECQFJa3eAvkx72eyQ==} engines: {node: '>=12'} cpu: [arm64] os: [android] - requiresBuild: true - dev: true - optional: true - /esbuild-darwin-64@0.14.54: + esbuild-darwin-64@0.14.54: resolution: {integrity: sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==} engines: {node: '>=12'} cpu: [x64] os: [darwin] - requiresBuild: true - dev: true - optional: true - /esbuild-darwin-64@0.15.7: + esbuild-darwin-64@0.15.7: resolution: {integrity: sha512-KGPt3r1c9ww009t2xLB6Vk0YyNOXh7hbjZ3EecHoVDxgtbUlYstMPDaReimKe6eOEfyY4hBEEeTvKwPsiH5WZg==} engines: {node: '>=12'} cpu: [x64] os: [darwin] - requiresBuild: true - dev: true - optional: true - /esbuild-darwin-arm64@0.14.54: + esbuild-darwin-arm64@0.14.54: resolution: {integrity: sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] - requiresBuild: true - dev: true - optional: true - /esbuild-darwin-arm64@0.15.7: + esbuild-darwin-arm64@0.15.7: resolution: {integrity: sha512-kBIHvtVqbSGajN88lYMnR3aIleH3ABZLLFLxwL2stiuIGAjGlQW741NxVTpUHQXUmPzxi6POqc9npkXa8AcSZQ==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] - requiresBuild: true - dev: true - optional: true - /esbuild-freebsd-64@0.14.54: + esbuild-freebsd-64@0.14.54: resolution: {integrity: sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] - requiresBuild: true - dev: true - optional: true - /esbuild-freebsd-64@0.15.7: + esbuild-freebsd-64@0.15.7: resolution: {integrity: sha512-hESZB91qDLV5MEwNxzMxPfbjAhOmtfsr9Wnuci7pY6TtEh4UDuevmGmkUIjX/b+e/k4tcNBMf7SRQ2mdNuK/HQ==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] - requiresBuild: true - dev: true - optional: true - /esbuild-freebsd-arm64@0.14.54: + esbuild-freebsd-arm64@0.14.54: resolution: {integrity: sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] - requiresBuild: true - dev: true - optional: true - /esbuild-freebsd-arm64@0.15.7: + esbuild-freebsd-arm64@0.15.7: resolution: {integrity: sha512-dLFR0ChH5t+b3J8w0fVKGvtwSLWCv7GYT2Y2jFGulF1L5HftQLzVGN+6pi1SivuiVSmTh28FwUhi9PwQicXI6Q==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] - requiresBuild: true - dev: true - optional: true - /esbuild-linux-32@0.14.54: + esbuild-linux-32@0.14.54: resolution: {integrity: sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==} engines: {node: '>=12'} cpu: [ia32] os: [linux] - requiresBuild: true - dev: true - optional: true - /esbuild-linux-32@0.15.7: + esbuild-linux-32@0.15.7: resolution: {integrity: sha512-v3gT/LsONGUZcjbt2swrMjwxo32NJzk+7sAgtxhGx1+ZmOFaTRXBAi1PPfgpeo/J//Un2jIKm/I+qqeo4caJvg==} engines: {node: '>=12'} cpu: [ia32] os: [linux] - requiresBuild: true - dev: true - optional: true - /esbuild-linux-64@0.14.54: + esbuild-linux-64@0.14.54: resolution: {integrity: sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==} engines: {node: '>=12'} cpu: [x64] os: [linux] - requiresBuild: true - dev: true - optional: true - /esbuild-linux-64@0.15.7: + esbuild-linux-64@0.15.7: resolution: {integrity: sha512-LxXEfLAKwOVmm1yecpMmWERBshl+Kv5YJ/1KnyAr6HRHFW8cxOEsEfisD3sVl/RvHyW//lhYUVSuy9jGEfIRAQ==} engines: {node: '>=12'} cpu: [x64] os: [linux] - requiresBuild: true - dev: true - optional: true - /esbuild-linux-arm64@0.14.54: + esbuild-linux-arm64@0.14.54: resolution: {integrity: sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==} engines: {node: '>=12'} cpu: [arm64] os: [linux] - requiresBuild: true - dev: true - optional: true - /esbuild-linux-arm64@0.15.7: + esbuild-linux-arm64@0.15.7: resolution: {integrity: sha512-P3cfhudpzWDkglutWgXcT2S7Ft7o2e3YDMrP1n0z2dlbUZghUkKCyaWw0zhp4KxEEzt/E7lmrtRu/pGWnwb9vw==} engines: {node: '>=12'} cpu: [arm64] os: [linux] - requiresBuild: true - dev: true - optional: true - /esbuild-linux-arm@0.14.54: + esbuild-linux-arm@0.14.54: resolution: {integrity: sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==} engines: {node: '>=12'} cpu: [arm] os: [linux] - requiresBuild: true - dev: true - optional: true - /esbuild-linux-arm@0.15.7: + esbuild-linux-arm@0.15.7: resolution: {integrity: sha512-JKgAHtMR5f75wJTeuNQbyznZZa+pjiUHV7sRZp42UNdyXC6TiUYMW/8z8yIBAr2Fpad8hM1royZKQisqPABPvQ==} engines: {node: '>=12'} cpu: [arm] os: [linux] - requiresBuild: true - dev: true - optional: true - /esbuild-linux-mips64le@0.14.54: + esbuild-linux-mips64le@0.14.54: resolution: {integrity: sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] - requiresBuild: true - dev: true - optional: true - /esbuild-linux-mips64le@0.15.7: + esbuild-linux-mips64le@0.15.7: resolution: {integrity: sha512-T7XKuxl0VpeFLCJXub6U+iybiqh0kM/bWOTb4qcPyDDwNVhLUiPcGdG2/0S7F93czUZOKP57YiLV8YQewgLHKw==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] - requiresBuild: true - dev: true - optional: true - /esbuild-linux-ppc64le@0.14.54: + esbuild-linux-ppc64le@0.14.54: resolution: {integrity: sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] - requiresBuild: true - dev: true - optional: true - /esbuild-linux-ppc64le@0.15.7: + esbuild-linux-ppc64le@0.15.7: resolution: {integrity: sha512-6mGuC19WpFN7NYbecMIJjeQgvDb5aMuvyk0PDYBJrqAEMkTwg3Z98kEKuCm6THHRnrgsdr7bp4SruSAxEM4eJw==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] - requiresBuild: true - dev: true - optional: true - /esbuild-linux-riscv64@0.14.54: + esbuild-linux-riscv64@0.14.54: resolution: {integrity: sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] - requiresBuild: true - dev: true - optional: true - /esbuild-linux-riscv64@0.15.7: + esbuild-linux-riscv64@0.15.7: resolution: {integrity: sha512-uUJsezbswAYo/X7OU/P+PuL/EI9WzxsEQXDekfwpQ23uGiooxqoLFAPmXPcRAt941vjlY9jtITEEikWMBr+F/g==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] - requiresBuild: true - dev: true - optional: true - /esbuild-linux-s390x@0.14.54: + esbuild-linux-s390x@0.14.54: resolution: {integrity: sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==} engines: {node: '>=12'} cpu: [s390x] os: [linux] - requiresBuild: true - dev: true - optional: true - /esbuild-linux-s390x@0.15.7: + esbuild-linux-s390x@0.15.7: resolution: {integrity: sha512-+tO+xOyTNMc34rXlSxK7aCwJgvQyffqEM5MMdNDEeMU3ss0S6wKvbBOQfgd5jRPblfwJ6b+bKiz0g5nABpY0QQ==} engines: {node: '>=12'} cpu: [s390x] os: [linux] - requiresBuild: true - dev: true - optional: true - /esbuild-netbsd-64@0.14.54: + esbuild-netbsd-64@0.14.54: resolution: {integrity: sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] - requiresBuild: true - dev: true - optional: true - /esbuild-netbsd-64@0.15.7: + esbuild-netbsd-64@0.15.7: resolution: {integrity: sha512-yVc4Wz+Pu3cP5hzm5kIygNPrjar/v5WCSoRmIjCPWfBVJkZNb5brEGKUlf+0Y759D48BCWa0WHrWXaNy0DULTQ==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] - requiresBuild: true - dev: true - optional: true - /esbuild-openbsd-64@0.14.54: + esbuild-openbsd-64@0.14.54: resolution: {integrity: sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] - requiresBuild: true - dev: true - optional: true - /esbuild-openbsd-64@0.15.7: + esbuild-openbsd-64@0.15.7: resolution: {integrity: sha512-GsimbwC4FSR4lN3wf8XmTQ+r8/0YSQo21rWDL0XFFhLHKlzEA4SsT1Tl8bPYu00IU6UWSJ+b3fG/8SB69rcuEQ==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] - requiresBuild: true - dev: true + + esbuild-sunos-64@0.14.54: + resolution: {integrity: sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + esbuild-sunos-64@0.15.7: + resolution: {integrity: sha512-8CDI1aL/ts0mDGbWzjEOGKXnU7p3rDzggHSBtVryQzkSOsjCHRVe0iFYUuhczlxU1R3LN/E7HgUO4NXzGGP/Ag==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + esbuild-windows-32@0.14.54: + resolution: {integrity: sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + esbuild-windows-32@0.15.7: + resolution: {integrity: sha512-cOnKXUEPS8EGCzRSFa1x6NQjGhGsFlVgjhqGEbLTPsA7x4RRYiy2RKoArNUU4iR2vHmzqS5Gr84MEumO/wxYKA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + esbuild-windows-64@0.14.54: + resolution: {integrity: sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + esbuild-windows-64@0.15.7: + resolution: {integrity: sha512-7MI08Ec2sTIDv+zH6StNBKO+2hGUYIT42GmFyW6MBBWWtJhTcQLinKS6ldIN1d52MXIbiJ6nXyCJ+LpL4jBm3Q==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + esbuild-windows-arm64@0.14.54: + resolution: {integrity: sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + esbuild-windows-arm64@0.15.7: + resolution: {integrity: sha512-R06nmqBlWjKHddhRJYlqDd3Fabx9LFdKcjoOy08YLimwmsswlFBJV4rXzZCxz/b7ZJXvrZgj8DDv1ewE9+StMw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + esbuild@0.14.54: + resolution: {integrity: sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==} + engines: {node: '>=12'} + hasBin: true + + esbuild@0.15.7: + resolution: {integrity: sha512-7V8tzllIbAQV1M4QoE52ImKu8hT/NLGlGXkiDsbEU5PS6K8Mn09ZnYoS+dcmHxOS9CRsV4IRAMdT3I67IyUNXw==} + engines: {node: '>=12'} + hasBin: true + + esbuild@0.16.17: + resolution: {integrity: sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==} + engines: {node: '>=12'} + hasBin: true + + escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + escodegen@2.0.0: + resolution: {integrity: sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==} + engines: {node: '>=6.0'} + hasBin: true + + eslint-config-airbnb-base@15.0.0: + resolution: {integrity: sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==} + engines: {node: ^10.12.0 || >=12.0.0} + peerDependencies: + eslint: ^7.32.0 || ^8.2.0 + eslint-plugin-import: ^2.25.2 + + eslint-config-airbnb-typescript@17.1.0: + resolution: {integrity: sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig==} + peerDependencies: + '@typescript-eslint/eslint-plugin': ^5.13.0 || ^6.0.0 + '@typescript-eslint/parser': ^5.0.0 || ^6.0.0 + eslint: ^7.32.0 || ^8.2.0 + eslint-plugin-import: ^2.25.3 + + eslint-config-airbnb@19.0.4: + resolution: {integrity: sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==} + engines: {node: ^10.12.0 || ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^7.32.0 || ^8.2.0 + eslint-plugin-import: ^2.25.3 + eslint-plugin-jsx-a11y: ^6.5.1 + eslint-plugin-react: ^7.28.0 + eslint-plugin-react-hooks: ^4.3.0 + + eslint-config-prettier@8.5.0: + resolution: {integrity: sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + + eslint-import-resolver-node@0.3.6: + resolution: {integrity: sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==} + + eslint-import-resolver-typescript@3.5.0: + resolution: {integrity: sha512-DEfpfuk+O/T5e9HBZOxocmwMuUGkvQQd5WRiMJF9kKNT9amByqOyGlWoAZAQiv0SZSy4GMtG1clmnvQA/RzA0A==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + + eslint-module-utils@2.7.4: + resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-import@2.26.0: + resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + + eslint-plugin-jsx-a11y@6.6.1: + resolution: {integrity: sha512-sXgFVNHiWffBq23uiS/JaP6eVR622DqwB4yTzKvGZGcPq6/yZ3WmOZfuBks/vHWo9GaFOqC2ZK4i6+C35knx7Q==} + engines: {node: '>=4.0'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + + eslint-plugin-react-hooks@4.6.0: + resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + + eslint-plugin-react@7.31.6: + resolution: {integrity: sha512-CXu4eu28sb8Sd2+cyUYsJVyDvpTlaXPG+bOzzpS9IzZKtye96AYX3ZmHQ6ayn/OAIQ/ufDJP8ElPWd63Pepn9w==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + + eslint-plugin-simple-import-sort@8.0.0: + resolution: {integrity: sha512-bXgJQ+lqhtQBCuWY/FUWdB27j4+lqcvXv5rUARkzbeWLwea+S5eBZEQrhnO+WgX3ZoJHVj0cn943iyXwByHHQw==} + peerDependencies: + eslint: '>=5.0.0' + + eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + + eslint-scope@7.1.1: + resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-utils@3.0.0: + resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} + engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} + peerDependencies: + eslint: '>=5' + + eslint-visitor-keys@2.1.0: + resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} + engines: {node: '>=10'} + + eslint-visitor-keys@3.3.0: + resolution: {integrity: sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint@8.23.0: + resolution: {integrity: sha512-pBG/XOn0MsJcKcTRLr27S5HpzQo4kLr+HjLQIyK4EiCsijDl/TB+h5uEuJU6bQ8Edvwz1XWOjpaP2qgnXGpTcA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + + espree@9.4.0: + resolution: {integrity: sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + esquery@1.4.0: + resolution: {integrity: sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + events@1.1.1: + resolution: {integrity: sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==} + engines: {node: '>=0.4.x'} + + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + + execa@6.1.0: + resolution: {integrity: sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + extendable-error@0.1.7: + resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} + + external-editor@3.1.0: + resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} + engines: {node: '>=4'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.2.11: + resolution: {integrity: sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fastq@1.13.0: + resolution: {integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==} + + file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + + fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + + filter-obj@1.1.0: + resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==} + engines: {node: '>=0.10.0'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + find-yarn-workspace-root2@1.2.16: + resolution: {integrity: sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA==} + + flat-cache@3.0.4: + resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} + engines: {node: ^10.12.0 || >=12.0.0} + + flatted@3.2.7: + resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} + + for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + + foreground-child@2.0.0: + resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==} + engines: {node: '>=8.0.0'} + + form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + + fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + + fs-extra@7.0.1: + resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} + engines: {node: '>=6 <7 || >=8'} + + fs-extra@8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.1: + resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.1.5: + resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} + engines: {node: '>= 0.4'} + + functional-red-black-tree@1.0.1: + resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-func-name@2.0.0: + resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} + + get-intrinsic@1.1.2: + resolution: {integrity: sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==} + + get-intrinsic@1.2.7: + resolution: {integrity: sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + get-symbol-description@1.0.0: + resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.2.0: + resolution: {integrity: sha512-X8u8fREiYOE6S8hLbq99PeykTDoLVnxvF4DjWKJmz9xy2nNRdUcV8ZN9tniJFeKyTU3qnC9lL8n4Chd6LmVKHg==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob-to-regexp@0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + + glob@7.1.6: + resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + + globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + + globals@13.17.0: + resolution: {integrity: sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==} + engines: {node: '>=8'} + + globalyzer@0.1.0: + resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==} + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + globby@13.1.2: + resolution: {integrity: sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + globrex@0.1.2: + resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.10: + resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} + + grapheme-splitter@1.0.4: + resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} + + graphql@16.8.0: + resolution: {integrity: sha512-0oKGaR+y3qcS5mCu1vb7KG+a89vjn06C7Ihq/dDl3jA+A8B3TKomvi3CiEcVLJQGalbu8F52LxkOym7U5sSfbg==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + + hard-rejection@2.1.0: + resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} + engines: {node: '>=6'} + + has-bigints@1.0.2: + resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.0: + resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.0: + resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + has@1.0.3: + resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} + engines: {node: '>= 0.4.0'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + hosted-git-info@2.8.9: + resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} + + html-encoding-sniffer@3.0.0: + resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==} + engines: {node: '>=12'} + + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + + http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + + http-proxy-agent@5.0.0: + resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} + engines: {node: '>= 6'} + + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + + human-id@1.0.2: + resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} + + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + human-signals@3.0.1: + resolution: {integrity: sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==} + engines: {node: '>=12.20.0'} + + husky@8.0.1: + resolution: {integrity: sha512-xs7/chUH/CKdOCs7Zy0Aev9e/dKOMZf3K1Az1nar3tzlv0jfqnYtu235bstsWTmXOR0EfINrPa97yy4Lz6RiKw==} + engines: {node: '>=14'} + hasBin: true + + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + ieee754@1.1.13: + resolution: {integrity: sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==} + + ignore@5.2.0: + resolution: {integrity: sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==} + engines: {node: '>= 4'} + + import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + internal-slot@1.0.3: + resolution: {integrity: sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==} + engines: {node: '>= 0.4'} + + is-arguments@1.2.0: + resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} + engines: {node: '>= 0.4'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-bigint@1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-boolean-object@1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + engines: {node: '>= 0.4'} + + is-callable@1.2.4: + resolution: {integrity: sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==} + engines: {node: '>= 0.4'} + + is-core-module@2.10.0: + resolution: {integrity: sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==} + + is-date-object@1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + engines: {node: '>= 0.4'} + + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-fullwidth-code-point@4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + + is-generator-function@1.1.0: + resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} + engines: {node: '>= 0.4'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-negative-zero@2.0.2: + resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} + engines: {node: '>= 0.4'} + + is-number-object@1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + engines: {node: '>= 0.4'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-plain-obj@1.1.0: + resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} + engines: {node: '>=0.10.0'} + + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + + is-regex@1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + engines: {node: '>= 0.4'} + + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.2: + resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} + + is-subdir@1.2.0: + resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} + engines: {node: '>=4'} + + is-symbol@1.0.4: + resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + + is-windows@1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + istanbul-lib-coverage@3.2.0: + resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} + engines: {node: '>=8'} + + istanbul-lib-report@3.0.0: + resolution: {integrity: sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==} + engines: {node: '>=8'} + + istanbul-reports@3.1.5: + resolution: {integrity: sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==} + engines: {node: '>=8'} + + jmespath@0.16.0: + resolution: {integrity: sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==} + engines: {node: '>= 0.6.0'} + + jose@4.14.4: + resolution: {integrity: sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==} + + joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + jsdom@20.0.3: + resolution: {integrity: sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==} + engines: {node: '>=14'} + peerDependencies: + canvas: ^2.5.0 + peerDependenciesMeta: + canvas: + optional: true + + jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonc-parser@3.2.0: + resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} + + jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + + jsx-ast-utils@3.3.3: + resolution: {integrity: sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==} + engines: {node: '>=4.0'} + + kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + + language-subtag-registry@0.3.22: + resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==} + + language-tags@1.0.5: + resolution: {integrity: sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==} + + levn@0.3.0: + resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==} + engines: {node: '>= 0.8.0'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lilconfig@2.0.5: + resolution: {integrity: sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==} + engines: {node: '>=10'} + + lilconfig@2.0.6: + resolution: {integrity: sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==} + engines: {node: '>=10'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + lint-staged@13.0.3: + resolution: {integrity: sha512-9hmrwSCFroTSYLjflGI8Uk+GWAwMB4OlpU4bMJEAT5d/llQwtYKoim4bLOyLCuWFAhWEupE0vkIFqtw/WIsPug==} + engines: {node: ^14.13.1 || >=16.0.0} + hasBin: true + + listr2@4.0.5: + resolution: {integrity: sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA==} + engines: {node: '>=12'} + peerDependencies: + enquirer: '>= 2.3.0 < 3' + peerDependenciesMeta: + enquirer: + optional: true + + load-tsconfig@0.2.3: + resolution: {integrity: sha512-iyT2MXws+dc2Wi6o3grCFtGXpeMvHmJqS27sMPGtV2eUu4PeFnG+33I8BlFK1t1NWMjOpcx9bridn5yxLDX2gQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + load-yaml-file@0.2.0: + resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==} + engines: {node: '>=6'} + + local-pkg@0.4.2: + resolution: {integrity: sha512-mlERgSPrbxU3BP4qBqAvvwlgW4MTg78iwJdGGnv7kibKjWcJksrG3t6LB5lXI93wXRDvG4NpUgJFmTG4T6rdrg==} + engines: {node: '>=14'} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash.sortby@4.7.0: + resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} + + lodash.startcase@4.4.0: + resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + + log-update@4.0.0: + resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==} + engines: {node: '>=10'} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + loupe@2.3.4: + resolution: {integrity: sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==} + + loupe@2.3.6: + resolution: {integrity: sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==} + + lru-cache@4.1.5: + resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + + lz-string@1.4.4: + resolution: {integrity: sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==} + hasBin: true + + magic-string@0.27.0: + resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} + engines: {node: '>=12'} + + make-dir@3.1.0: + resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} + engines: {node: '>=8'} + + map-obj@1.0.1: + resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} + engines: {node: '>=0.10.0'} + + map-obj@4.3.0: + resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} + engines: {node: '>=8'} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + + meow@6.1.1: + resolution: {integrity: sha512-3YffViIt2QWgTy6Pale5QpopX/IvU3LPL03jOTqp6pGj3VjesdO/U8CuHMKpnQr4shCNCM5fd5XFFvIIl6JBHg==} + engines: {node: '>=8'} + + merge-descriptors@1.0.1: + resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + methods@1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} + + micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + + min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.3: + resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist-options@4.1.0: + resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} + engines: {node: '>= 6'} + + minimist@1.2.6: + resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==} + + mixme@0.5.5: + resolution: {integrity: sha512-/6IupbRx32s7jjEwHcycXikJwFD5UujbVNuJFkeKLYje+92OvtuPniF6JhnFm5JCTDUhS+kYK3W/4BWYQYXz7w==} + engines: {node: '>= 8.0.0'} + + mlly@1.1.0: + resolution: {integrity: sha512-cwzBrBfwGC1gYJyfcy8TcZU1f+dbH/T+TuOhtYP2wLv/Fb51/uV7HJQfBPtEupZ2ORLRU1EKFS/QfS3eo9+kBQ==} + + ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + + nanoid@3.3.4: + resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + + next@12.3.0: + resolution: {integrity: sha512-GpzI6me9V1+XYtfK0Ae9WD0mKqHyzQlGq1xH1rzNIYMASo4Tkl4rTe9jSqtBpXFhOS33KohXs9ZY38Akkhdciw==} + engines: {node: '>=12.22.0'} + hasBin: true + peerDependencies: + fibers: '>= 3.1.0' + node-sass: ^6.0.0 || ^7.0.0 + react: ^17.0.2 || ^18.0.0-0 + react-dom: ^17.0.2 || ^18.0.0-0 + sass: ^1.3.0 + peerDependenciesMeta: + fibers: + optional: true + node-sass: + optional: true + sass: + optional: true + + node-mocks-http@1.11.0: + resolution: {integrity: sha512-jS/WzSOcKbOeGrcgKbenZeNhxUNnP36Yw11+hL4TTxQXErGfqYZ+MaYNNvhaTiGIJlzNSqgQkk9j8dSu1YWSuw==} + engines: {node: '>=0.6'} + + node-releases@2.0.6: + resolution: {integrity: sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==} + + normalize-package-data@2.5.0: + resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + npm-run-path@5.1.0: + resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + nwsapi@2.2.2: + resolution: {integrity: sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.12.2: + resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.4: + resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} + engines: {node: '>= 0.4'} + + object.entries@1.1.5: + resolution: {integrity: sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.5: + resolution: {integrity: sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==} + engines: {node: '>= 0.4'} + + object.hasown@1.1.1: + resolution: {integrity: sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==} + + object.values@1.1.5: + resolution: {integrity: sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==} + engines: {node: '>= 0.4'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + + open@8.4.0: + resolution: {integrity: sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==} + engines: {node: '>=12'} + + optionator@0.8.3: + resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} + engines: {node: '>= 0.8.0'} + + optionator@0.9.1: + resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} + engines: {node: '>= 0.8.0'} + + os-tmpdir@1.0.2: + resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} + engines: {node: '>=0.10.0'} + + outdent@0.5.0: + resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} + + p-filter@2.1.0: + resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} + engines: {node: '>=8'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-limit@4.0.0: + resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p-map@2.1.0: + resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} + engines: {node: '>=6'} + + p-map@4.0.0: + resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} + engines: {node: '>=10'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + parse5@7.1.1: + resolution: {integrity: sha512-kwpuwzB+px5WUg9pyK0IcK/shltJN5/OVhQagxhCQNtT9Y9QRZqNY2e1cmbu/paRh5LMnz/oVTVLBpjFmMZhSg==} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + pathe@0.2.0: + resolution: {integrity: sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==} + + pathe@1.0.0: + resolution: {integrity: sha512-nPdMG0Pd09HuSsr7QOKUXO2Jr9eqaDiZvDwdyIhNG5SHYujkQHYKDfGQkulBxvbDHz8oHLsTgKN86LSwYzSHAg==} + + pathe@1.1.0: + resolution: {integrity: sha512-ODbEPR0KKHqECXW1GoxdDb+AZvULmXjVPy4rt+pGo2+TnjJTIPJQSVS6N63n8T2Ip+syHhbn52OewKicV0373w==} + + pathval@1.1.1: + resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + + picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pidtree@0.6.0: + resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} + engines: {node: '>=0.10'} + hasBin: true + + pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + + pirates@4.0.5: + resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==} + engines: {node: '>= 6'} + + pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + + pkg-types@1.0.1: + resolution: {integrity: sha512-jHv9HB+Ho7dj6ItwppRDDl0iZRYBD0jsakHXtFgoLr+cHSF6xC+QL54sJmWxyGxOLYSHm0afhXhXcQDQqH9z8g==} + + possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + + postcss-load-config@3.1.4: + resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} + engines: {node: '>= 10'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + + postcss@8.4.14: + resolution: {integrity: sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.4.21: + resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==} + engines: {node: ^10 || ^12 || >=14} + + preferred-pm@3.0.3: + resolution: {integrity: sha512-+wZgbxNES/KlJs9q40F/1sfOd/j7f1O9JaHcW5Dsn3aUUOZg3L2bjpVUcKV2jvtElYfoTuQiNeMfQJ4kwUAhCQ==} + engines: {node: '>=10'} + + prelude-ls@1.1.2: + resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} + engines: {node: '>= 0.8.0'} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier@2.7.1: + resolution: {integrity: sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==} + engines: {node: '>=10.13.0'} + hasBin: true + + pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + + pseudomap@1.0.2: + resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} + + psl@1.9.0: + resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} + + punycode@1.3.2: + resolution: {integrity: sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==} + + punycode@2.1.1: + resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} + engines: {node: '>=6'} + + query-string@7.1.3: + resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==} + engines: {node: '>=6'} + + querystring@0.2.0: + resolution: {integrity: sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==} + engines: {node: '>=0.4.x'} + deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead. + + querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + quick-lru@4.0.1: + resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} + engines: {node: '>=8'} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@2.5.2: + resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} + engines: {node: '>= 0.8'} + + react-dom@18.2.0: + resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} + peerDependencies: + react: ^18.2.0 + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + + react-refresh@0.14.0: + resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} + engines: {node: '>=0.10.0'} + + react@18.2.0: + resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} + engines: {node: '>=0.10.0'} + + read-pkg-up@7.0.1: + resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} + engines: {node: '>=8'} + + read-pkg@5.2.0: + resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} + engines: {node: '>=8'} + + read-yaml-file@1.1.0: + resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} + engines: {node: '>=6'} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + redent@3.0.0: + resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} + engines: {node: '>=8'} + + regenerator-runtime@0.13.11: + resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + + regenerator-runtime@0.13.9: + resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==} + + regexp.prototype.flags@1.4.3: + resolution: {integrity: sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==} + engines: {node: '>= 0.4'} + + regexpp@3.2.0: + resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} + engines: {node: '>=8'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + + requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve@1.22.1: + resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} + hasBin: true + + resolve@2.0.0-next.4: + resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==} + hasBin: true + + restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + + retes@0.33.0: + resolution: {integrity: sha512-I6V1G2JkJ2JFIFSVuultNXepf7BW8SCaSUOq5IETM2fDjFim5Dg5F1zU/QbplNW0mqkk8QCw+I722v3nPkpRlA==} + + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rfdc@1.3.0: + resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==} + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + + rollup@2.79.0: + resolution: {integrity: sha512-x4KsrCgwQ7ZJPcFA/SUu6QVcYlO7uRLfLAy0DSA4NS2eG8japdbpM50ToH7z4iObodRYOJ0soneF0iaQRJ6zhA==} + engines: {node: '>=10.0.0'} + hasBin: true + + rollup@3.10.1: + resolution: {integrity: sha512-3Er+yel3bZbZX1g2kjVM+FW+RUWDxbG87fcqFM5/9HbPCTpbVp6JOLn7jlxnNlbu7s/N/uDA4EV/91E2gWnxzw==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + rxjs@7.5.6: + resolution: {integrity: sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw==} + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + sax@1.2.1: + resolution: {integrity: sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==} + + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + + scheduler@0.23.0: + resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} + + semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + + semver@6.3.0: + resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} + hasBin: true + + semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + + semver@7.6.0: + resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} + engines: {node: '>=10'} + hasBin: true + + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + shebang-command@1.2.0: + resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} + engines: {node: '>=0.10.0'} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@1.0.0: + resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} + engines: {node: '>=0.10.0'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel@1.0.4: + resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + slash@4.0.0: + resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} + engines: {node: '>=12'} + + slice-ansi@3.0.0: + resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} + engines: {node: '>=8'} + + slice-ansi@4.0.0: + resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} + engines: {node: '>=10'} + + slice-ansi@5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + + smartwrap@2.0.2: + resolution: {integrity: sha512-vCsKNQxb7PnCNd2wY1WClWifAc2lwqsG8OaswpJkVJsvMGcnEntdTCDajZCkk93Ay1U3t/9puJmb525Rg5MZBA==} + engines: {node: '>=6'} + hasBin: true + + source-map-js@1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + engines: {node: '>=0.10.0'} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + source-map@0.8.0-beta.0: + resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} + engines: {node: '>= 8'} + + spawndamnit@2.0.0: + resolution: {integrity: sha512-j4JKEcncSjFlqIwU5L/rp2N5SIPsdxaRsIv678+TZxZ0SRDJTm8JrxJMjE/XuiEZNEir3S8l0Fa3Ke339WI4qA==} + + spdx-correct@3.1.1: + resolution: {integrity: sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==} + + spdx-exceptions@2.3.0: + resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} + + spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + + spdx-license-ids@3.0.12: + resolution: {integrity: sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==} + + split-on-first@1.1.0: + resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==} + engines: {node: '>=6'} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + + std-env@3.3.1: + resolution: {integrity: sha512-3H20QlwQsSm2OvAxWIYhs+j01MzzqwMwGiiO1NQaJYZgJZFPuAbf95/DiKRBSTYIJ2FeGUc+B/6mPGcWP9dO3Q==} + + stream-transform@2.1.3: + resolution: {integrity: sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==} + + streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + + strict-uri-encode@2.0.0: + resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} + engines: {node: '>=4'} + + string-argv@0.3.1: + resolution: {integrity: sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==} + engines: {node: '>=0.6.19'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string.prototype.matchall@4.0.7: + resolution: {integrity: sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==} + + string.prototype.trimend@1.0.5: + resolution: {integrity: sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==} + + string.prototype.trimstart@1.0.5: + resolution: {integrity: sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.0.1: + resolution: {integrity: sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==} + engines: {node: '>=12'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + + strip-indent@3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + strip-literal@1.0.0: + resolution: {integrity: sha512-5o4LsH1lzBzO9UFH63AJ2ad2/S2AVx6NtjOcaz+VTT2h1RiRvbipW72z8M/lxEhcPHDBQwpDrnTF7sXy/7OwCQ==} + + styled-jsx@5.0.6: + resolution: {integrity: sha512-xOeROtkK5MGMDimBQ3J6iPId8q0t/BDoG5XN6oKkZClVz9ISF/hihN8OCn2LggMU6N32aXnrXBdn3auSqNS9fA==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + + sucrase@3.25.0: + resolution: {integrity: sha512-WxTtwEYXSmZArPGStGBicyRsg5TBEFhT5b7N+tF+zauImP0Acy+CoUK0/byJ8JNPK/5lbpWIVuFagI4+0l85QQ==} + engines: {node: '>=8'} + hasBin: true + + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + + synckit@0.8.4: + resolution: {integrity: sha512-Dn2ZkzMdSX827QbowGbU/4yjWuvNaCoScLLoMo/yKbu+P4GBR6cRGKZH27k6a9bRzdqcyd1DE96pQtQ6uNkmyw==} + engines: {node: ^14.18.0 || >=16.0.0} + + tapable@2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} + engines: {node: '>=6'} + + term-size@2.2.1: + resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} + engines: {node: '>=8'} + + test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + + tiny-glob@0.2.9: + resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} + + tinybench@2.3.1: + resolution: {integrity: sha512-hGYWYBMPr7p4g5IarQE7XhlyWveh1EKhy4wUBS1LrHXCKYgvz+4/jCqgmJqZxxldesn05vccrtME2RLLZNW7iA==} + + tinypool@0.3.0: + resolution: {integrity: sha512-NX5KeqHOBZU6Bc0xj9Vr5Szbb1j8tUHIeD18s41aDJaPeC5QTdEhK0SpdpUrZlj2nv5cctNcSjaKNanXlfcVEQ==} + engines: {node: '>=14.0.0'} + + tinyspy@1.0.2: + resolution: {integrity: sha512-bSGlgwLBYf7PnUsQ6WOc6SJ3pGOcd+d8AA6EUnLDDM0kWEstC1JIlSZA3UNliDXhd9ABoS7hiRBDCu+XP/sf1Q==} + engines: {node: '>=14.0.0'} + + tmp@0.0.33: + resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} + engines: {node: '>=0.6.0'} + + to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + tough-cookie@4.1.3: + resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==} + engines: {node: '>=6'} + + tr46@1.0.1: + resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} + + tr46@3.0.0: + resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==} + engines: {node: '>=12'} + + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + + trim-newlines@3.0.1: + resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} + engines: {node: '>=8'} + + ts-api-utils@1.2.1: + resolution: {integrity: sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' + + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + + tsconfig-paths@3.14.1: + resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==} + + tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + + tslib@2.4.0: + resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} + + tsm@2.2.2: + resolution: {integrity: sha512-bXkt675NbbqfwRHSSn8kSNEEHvoIUFDM9G6tUENkjEKpAEbrEzieO3PxUiRJylMw8fEGpcf5lSjadzzz12pc2A==} + engines: {node: '>=12'} + hasBin: true + + tsup@6.2.3: + resolution: {integrity: sha512-J5Pu2Dx0E1wlpIEsVFv9ryzP1pZ1OYsJ2cBHZ7GrKteytNdzaSz5hmLX7/nAxtypq+jVkVvA79d7S83ETgHQ5w==} + engines: {node: '>=14'} + hasBin: true + peerDependencies: + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: ^4.1.0 + peerDependenciesMeta: + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + + tsutils@3.21.0: + resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} + engines: {node: '>= 6'} + peerDependencies: + typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + + tty-table@4.1.6: + resolution: {integrity: sha512-kRj5CBzOrakV4VRRY5kUWbNYvo/FpOsz65DzI5op9P+cHov3+IqPbo1JE1ZnQGkHdZgNFDsrEjrfqqy/Ply9fw==} + engines: {node: '>=8.0.0'} + hasBin: true + + type-check@0.3.2: + resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} + engines: {node: '>= 0.8.0'} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + + type-fest@0.13.1: + resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} + engines: {node: '>=10'} + + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + + type-fest@0.6.0: + resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} + engines: {node: '>=8'} + + type-fest@0.8.1: + resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} + engines: {node: '>=8'} + + type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + + typescript@5.4.2: + resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==} + engines: {node: '>=14.17'} + hasBin: true + + ufo@1.0.1: + resolution: {integrity: sha512-boAm74ubXHY7KJQZLlXrtMz52qFvpsbOxDcZOnw/Wf+LS4Mmyu7JxmzD4tDLtUQtmZECypJ0FrCz4QIe6dvKRA==} + + unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + + universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + + universalify@0.2.0: + resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} + engines: {node: '>= 4.0.0'} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + update-browserslist-db@1.0.7: + resolution: {integrity: sha512-iN/XYesmZ2RmmWAiI4Z5rq0YqSiv0brj9Ce9CfhNE4xIW2h+MFxcgkxIzZ+ShkFPUkjU3gQ+3oypadD3RAMtrg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + + url@0.10.3: + resolution: {integrity: sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==} + + use-sync-external-store@1.2.0: + resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + + util@0.12.5: + resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} + + uuid@8.0.0: + resolution: {integrity: sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==} + hasBin: true + + uuid@9.0.0: + resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==} + hasBin: true + + v8-to-istanbul@9.0.1: + resolution: {integrity: sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==} + engines: {node: '>=10.12.0'} + + validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + + vi-fetch@0.8.0: + resolution: {integrity: sha512-uvEgEBTacSnlxRcoA56Drwkc2LbTvRNOdSx5MVayBfEsHAgQJAu+LwePlUOkidFsqQMcQxcb+LlC9qZ9v1yXiw==} + + vite-node@0.27.2: + resolution: {integrity: sha512-IDwuVhslF10qCnWOGJui7/2KksAOBHi+UbVo6Pqt4f5lgn+kS2sVvYDsETRG5PSuslisGB5CFGvb9I6FQgymBQ==} + engines: {node: '>=v14.16.0'} + hasBin: true + + vite-node@0.28.1: + resolution: {integrity: sha512-Mmab+cIeElkVn4noScCRjy8nnQdh5LDIR4QCH/pVWtY15zv5Z1J7u6/471B9JZ2r8CEIs42vTbngaamOVkhPLA==} + engines: {node: '>=v14.16.0'} + hasBin: true + + vite@4.0.5: + resolution: {integrity: sha512-7m87RC+caiAxG+8j3jObveRLqaWA/neAdCat6JAZwMkSWqFHOvg8MYe5fAQxVBRAuKAQ1S6XDh3CBQuLNbY33w==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + vitest@0.27.2: + resolution: {integrity: sha512-y7tdsL2uaQy+KF18AlmNHZe29ukyFytlxrpSTwwmgLE2XHR/aPucJP9FLjWoqjgqFlXzRAjHlFJLU+HDyI/OsA==} + engines: {node: '>=v14.16.0'} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@vitest/browser': '*' + '@vitest/ui': '*' + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + vitest@0.28.1: + resolution: {integrity: sha512-F6wAO3K5+UqJCCGt0YAl3Ila2f+fpBrJhl9n7qWEhREwfzQeXlMkkCqGqGtzBxCSa8kv5QHrkshX8AaPTXYACQ==} + engines: {node: '>=v14.16.0'} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@vitest/browser': '*' + '@vitest/ui': '*' + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + w3c-xmlserializer@4.0.0: + resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==} + engines: {node: '>=14'} + + watchpack@2.4.2: + resolution: {integrity: sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==} + engines: {node: '>=10.13.0'} + + wcwidth@1.0.1: + resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + + webidl-conversions@4.0.2: + resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} + + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + + whatwg-encoding@2.0.0: + resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} + engines: {node: '>=12'} + + whatwg-mimetype@3.0.0: + resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} + engines: {node: '>=12'} + + whatwg-url@11.0.0: + resolution: {integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==} + engines: {node: '>=12'} + + whatwg-url@7.1.0: + resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} + + which-boxed-primitive@1.0.2: + resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + + which-module@2.0.0: + resolution: {integrity: sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==} + + which-pm@2.0.0: + resolution: {integrity: sha512-Lhs9Pmyph0p5n5Z3mVnN0yWcbQYUAD7rbQUiMsQxOJ3T57k7RFe35SUwWMf7dsbDZks1uOmw4AecB/JMDj3v/w==} + engines: {node: '>=8.15'} + + which-typed-array@1.1.18: + resolution: {integrity: sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==} + engines: {node: '>= 0.4'} + + which@1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + why-is-node-running@2.2.2: + resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==} + engines: {node: '>=8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@8.11.0: + resolution: {integrity: sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + xml-name-validator@4.0.0: + resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} + engines: {node: '>=12'} + + xml2js@0.6.2: + resolution: {integrity: sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==} + engines: {node: '>=4.0.0'} + + xmlbuilder@11.0.1: + resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} + engines: {node: '>=4.0'} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@2.1.2: + resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + + yaml@2.1.3: + resolution: {integrity: sha512-AacA8nRULjKMX2DvWvOAdBZMOfQlypSFkjcOcu9FalllIDJ1kvlREzcdIZmidQUqqeMv7jorHjq2HlLv/+c2lg==} + engines: {node: '>= 14'} + + yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + + yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + + yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + + yargs@17.6.2: + resolution: {integrity: sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==} + engines: {node: '>=12'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + yocto-queue@1.0.0: + resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} + engines: {node: '>=12.20'} + + zod@3.19.1: + resolution: {integrity: sha512-LYjZsEDhCdYET9ikFu6dVPGp2YH9DegXjdJToSzD9rO6fy4qiRYFoyEYwps88OseJlPyl2NOe2iJuhEhL7IpEA==} + +publishDirectory: dist + +snapshots: + + '@ampproject/remapping@2.2.0': + dependencies: + '@jridgewell/gen-mapping': 0.1.1 + '@jridgewell/trace-mapping': 0.3.15 + + '@babel/code-frame@7.18.6': + dependencies: + '@babel/highlight': 7.18.6 + + '@babel/compat-data@7.20.10': {} + + '@babel/core@7.20.12': + dependencies: + '@ampproject/remapping': 2.2.0 + '@babel/code-frame': 7.18.6 + '@babel/generator': 7.20.7 + '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.20.12) + '@babel/helper-module-transforms': 7.20.11 + '@babel/helpers': 7.20.7 + '@babel/parser': 7.20.7 + '@babel/template': 7.20.7 + '@babel/traverse': 7.20.12 + '@babel/types': 7.20.7 + convert-source-map: 1.8.0 + debug: 4.3.4 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.0 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.20.7': + dependencies: + '@babel/types': 7.20.7 + '@jridgewell/gen-mapping': 0.3.2 + jsesc: 2.5.2 + + '@babel/helper-compilation-targets@7.20.7(@babel/core@7.20.12)': + dependencies: + '@babel/compat-data': 7.20.10 + '@babel/core': 7.20.12 + '@babel/helper-validator-option': 7.18.6 + browserslist: 4.21.3 + lru-cache: 5.1.1 + semver: 6.3.0 + + '@babel/helper-environment-visitor@7.18.9': {} + + '@babel/helper-function-name@7.19.0': + dependencies: + '@babel/template': 7.20.7 + '@babel/types': 7.20.7 + + '@babel/helper-hoist-variables@7.18.6': + dependencies: + '@babel/types': 7.20.7 + + '@babel/helper-module-imports@7.18.6': + dependencies: + '@babel/types': 7.20.7 + + '@babel/helper-module-transforms@7.20.11': + dependencies: + '@babel/helper-environment-visitor': 7.18.9 + '@babel/helper-module-imports': 7.18.6 + '@babel/helper-simple-access': 7.20.2 + '@babel/helper-split-export-declaration': 7.18.6 + '@babel/helper-validator-identifier': 7.19.1 + '@babel/template': 7.20.7 + '@babel/traverse': 7.20.12 + '@babel/types': 7.20.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.18.9': {} + + '@babel/helper-plugin-utils@7.20.2': {} + + '@babel/helper-simple-access@7.20.2': + dependencies: + '@babel/types': 7.20.7 + + '@babel/helper-split-export-declaration@7.18.6': + dependencies: + '@babel/types': 7.20.7 + + '@babel/helper-string-parser@7.19.4': {} + + '@babel/helper-validator-identifier@7.18.6': {} + + '@babel/helper-validator-identifier@7.19.1': {} + + '@babel/helper-validator-option@7.18.6': {} + + '@babel/helpers@7.20.7': + dependencies: + '@babel/template': 7.20.7 + '@babel/traverse': 7.20.12 + '@babel/types': 7.20.7 + transitivePeerDependencies: + - supports-color + + '@babel/highlight@7.18.6': + dependencies: + '@babel/helper-validator-identifier': 7.18.6 + chalk: 2.4.2 + js-tokens: 4.0.0 + + '@babel/parser@7.20.7': + dependencies: + '@babel/types': 7.20.7 + + '@babel/plugin-transform-react-jsx-self@7.18.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.18.9 + + '@babel/plugin-transform-react-jsx-source@7.19.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + + '@babel/runtime-corejs3@7.18.9': + dependencies: + core-js-pure: 3.25.0 + regenerator-runtime: 0.13.9 + + '@babel/runtime@7.18.9': + dependencies: + regenerator-runtime: 0.13.9 + + '@babel/runtime@7.20.13': + dependencies: + regenerator-runtime: 0.13.11 + + '@babel/template@7.20.7': + dependencies: + '@babel/code-frame': 7.18.6 + '@babel/parser': 7.20.7 + '@babel/types': 7.20.7 + + '@babel/traverse@7.20.12': + dependencies: + '@babel/code-frame': 7.18.6 + '@babel/generator': 7.20.7 + '@babel/helper-environment-visitor': 7.18.9 + '@babel/helper-function-name': 7.19.0 + '@babel/helper-hoist-variables': 7.18.6 + '@babel/helper-split-export-declaration': 7.18.6 + '@babel/parser': 7.20.7 + '@babel/types': 7.20.7 + debug: 4.3.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.20.7': + dependencies: + '@babel/helper-string-parser': 7.19.4 + '@babel/helper-validator-identifier': 7.19.1 + to-fast-properties: 2.0.0 + + '@bcoe/v8-coverage@0.2.3': {} + + '@changesets/apply-release-plan@7.0.0': + dependencies: + '@babel/runtime': 7.20.13 + '@changesets/config': 3.0.0 + '@changesets/get-version-range-type': 0.4.0 + '@changesets/git': 3.0.0 + '@changesets/types': 6.0.0 + '@manypkg/get-packages': 1.1.3 + detect-indent: 6.1.0 + fs-extra: 7.0.1 + lodash.startcase: 4.4.0 + outdent: 0.5.0 + prettier: 2.7.1 + resolve-from: 5.0.0 + semver: 7.5.4 + + '@changesets/assemble-release-plan@6.0.0': + dependencies: + '@babel/runtime': 7.20.13 + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.0.0 + '@changesets/types': 6.0.0 + '@manypkg/get-packages': 1.1.3 + semver: 7.5.4 + + '@changesets/changelog-git@0.2.0': + dependencies: + '@changesets/types': 6.0.0 + + '@changesets/cli@2.27.1': + dependencies: + '@babel/runtime': 7.20.13 + '@changesets/apply-release-plan': 7.0.0 + '@changesets/assemble-release-plan': 6.0.0 + '@changesets/changelog-git': 0.2.0 + '@changesets/config': 3.0.0 + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.0.0 + '@changesets/get-release-plan': 4.0.0 + '@changesets/git': 3.0.0 + '@changesets/logger': 0.1.0 + '@changesets/pre': 2.0.0 + '@changesets/read': 0.6.0 + '@changesets/types': 6.0.0 + '@changesets/write': 0.3.0 + '@manypkg/get-packages': 1.1.3 + '@types/semver': 7.5.0 + ansi-colors: 4.1.3 + chalk: 2.4.2 + ci-info: 3.9.0 + enquirer: 2.3.6 + external-editor: 3.1.0 + fs-extra: 7.0.1 + human-id: 1.0.2 + meow: 6.1.1 + outdent: 0.5.0 + p-limit: 2.3.0 + preferred-pm: 3.0.3 + resolve-from: 5.0.0 + semver: 7.5.4 + spawndamnit: 2.0.0 + term-size: 2.2.1 + tty-table: 4.1.6 + + '@changesets/config@3.0.0': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.0.0 + '@changesets/logger': 0.1.0 + '@changesets/types': 6.0.0 + '@manypkg/get-packages': 1.1.3 + fs-extra: 7.0.1 + micromatch: 4.0.5 + + '@changesets/errors@0.2.0': + dependencies: + extendable-error: 0.1.7 + + '@changesets/get-dependents-graph@2.0.0': + dependencies: + '@changesets/types': 6.0.0 + '@manypkg/get-packages': 1.1.3 + chalk: 2.4.2 + fs-extra: 7.0.1 + semver: 7.5.4 + + '@changesets/get-release-plan@4.0.0': + dependencies: + '@babel/runtime': 7.20.13 + '@changesets/assemble-release-plan': 6.0.0 + '@changesets/config': 3.0.0 + '@changesets/pre': 2.0.0 + '@changesets/read': 0.6.0 + '@changesets/types': 6.0.0 + '@manypkg/get-packages': 1.1.3 + + '@changesets/get-version-range-type@0.4.0': {} + + '@changesets/git@3.0.0': + dependencies: + '@babel/runtime': 7.20.13 + '@changesets/errors': 0.2.0 + '@changesets/types': 6.0.0 + '@manypkg/get-packages': 1.1.3 + is-subdir: 1.2.0 + micromatch: 4.0.5 + spawndamnit: 2.0.0 + + '@changesets/logger@0.1.0': + dependencies: + chalk: 2.4.2 + + '@changesets/parse@0.4.0': + dependencies: + '@changesets/types': 6.0.0 + js-yaml: 3.14.1 + + '@changesets/pre@2.0.0': + dependencies: + '@babel/runtime': 7.20.13 + '@changesets/errors': 0.2.0 + '@changesets/types': 6.0.0 + '@manypkg/get-packages': 1.1.3 + fs-extra: 7.0.1 + + '@changesets/read@0.6.0': + dependencies: + '@babel/runtime': 7.20.13 + '@changesets/git': 3.0.0 + '@changesets/logger': 0.1.0 + '@changesets/parse': 0.4.0 + '@changesets/types': 6.0.0 + chalk: 2.4.2 + fs-extra: 7.0.1 + p-filter: 2.1.0 + + '@changesets/types@4.1.0': {} + + '@changesets/types@6.0.0': {} + + '@changesets/write@0.3.0': + dependencies: + '@babel/runtime': 7.20.13 + '@changesets/types': 6.0.0 + fs-extra: 7.0.1 + human-id: 1.0.2 + prettier: 2.7.1 + + '@esbuild/android-arm64@0.16.17': + optional: true + + '@esbuild/android-arm@0.16.17': + optional: true + + '@esbuild/android-x64@0.16.17': + optional: true + + '@esbuild/darwin-arm64@0.16.17': + optional: true + + '@esbuild/darwin-x64@0.16.17': + optional: true + + '@esbuild/freebsd-arm64@0.16.17': + optional: true + + '@esbuild/freebsd-x64@0.16.17': + optional: true + + '@esbuild/linux-arm64@0.16.17': + optional: true + + '@esbuild/linux-arm@0.16.17': + optional: true + + '@esbuild/linux-ia32@0.16.17': + optional: true + + '@esbuild/linux-loong64@0.14.54': + optional: true + + '@esbuild/linux-loong64@0.15.7': + optional: true + + '@esbuild/linux-loong64@0.16.17': + optional: true + + '@esbuild/linux-mips64el@0.16.17': + optional: true + + '@esbuild/linux-ppc64@0.16.17': + optional: true + + '@esbuild/linux-riscv64@0.16.17': + optional: true + + '@esbuild/linux-s390x@0.16.17': + optional: true + + '@esbuild/linux-x64@0.16.17': + optional: true + + '@esbuild/netbsd-x64@0.16.17': + optional: true + + '@esbuild/openbsd-x64@0.16.17': + optional: true + + '@esbuild/sunos-x64@0.16.17': + optional: true + + '@esbuild/win32-arm64@0.16.17': + optional: true + + '@esbuild/win32-ia32@0.16.17': + optional: true + + '@esbuild/win32-x64@0.16.17': + optional: true + + '@eslint/eslintrc@1.3.1': + dependencies: + ajv: 6.12.6 + debug: 4.3.4 + espree: 9.4.0 + globals: 13.17.0 + ignore: 5.2.0 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@humanwhocodes/config-array@0.10.4': + dependencies: + '@humanwhocodes/object-schema': 1.2.1 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@humanwhocodes/gitignore-to-minimatch@1.0.2': {} + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/object-schema@1.2.1': {} + + '@istanbuljs/schema@0.1.3': {} + + '@jridgewell/gen-mapping@0.1.1': + dependencies: + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.14 + + '@jridgewell/gen-mapping@0.3.2': + dependencies: + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.14 + '@jridgewell/trace-mapping': 0.3.15 + + '@jridgewell/resolve-uri@3.1.0': {} + + '@jridgewell/set-array@1.1.2': {} + + '@jridgewell/sourcemap-codec@1.4.14': {} + + '@jridgewell/trace-mapping@0.3.15': + dependencies: + '@jridgewell/resolve-uri': 3.1.0 + '@jridgewell/sourcemap-codec': 1.4.14 + + '@manypkg/find-root@1.1.0': + dependencies: + '@babel/runtime': 7.20.13 + '@types/node': 12.20.55 + find-up: 4.1.0 + fs-extra: 8.1.0 + + '@manypkg/get-packages@1.1.3': + dependencies: + '@babel/runtime': 7.20.13 + '@changesets/types': 4.1.0 + '@manypkg/find-root': 1.1.0 + fs-extra: 8.1.0 + globby: 11.1.0 + read-yaml-file: 1.1.0 + + '@next/env@12.3.0': {} + + '@next/swc-android-arm-eabi@12.3.0': + optional: true + + '@next/swc-android-arm64@12.3.0': + optional: true + + '@next/swc-darwin-arm64@12.3.0': + optional: true + + '@next/swc-darwin-x64@12.3.0': + optional: true + + '@next/swc-freebsd-x64@12.3.0': + optional: true + + '@next/swc-linux-arm-gnueabihf@12.3.0': + optional: true + + '@next/swc-linux-arm64-gnu@12.3.0': + optional: true + + '@next/swc-linux-arm64-musl@12.3.0': + optional: true + + '@next/swc-linux-x64-gnu@12.3.0': + optional: true + + '@next/swc-linux-x64-musl@12.3.0': + optional: true + + '@next/swc-win32-arm64-msvc@12.3.0': + optional: true + + '@next/swc-win32-ia32-msvc@12.3.0': + optional: true + + '@next/swc-win32-x64-msvc@12.3.0': + optional: true + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.13.0 + + '@opentelemetry/api@1.7.0': {} + + '@opentelemetry/semantic-conventions@1.18.1': {} + + '@pkgr/utils@2.3.1': + dependencies: + cross-spawn: 7.0.3 + is-glob: 4.0.3 + open: 8.4.0 + picocolors: 1.0.0 + tiny-glob: 0.2.9 + tslib: 2.4.0 + + '@swc/helpers@0.4.11': + dependencies: + tslib: 2.4.0 + + '@testing-library/dom@8.17.1': + dependencies: + '@babel/code-frame': 7.18.6 + '@babel/runtime': 7.18.9 + '@types/aria-query': 4.2.2 + aria-query: 5.0.2 + chalk: 4.1.2 + dom-accessibility-api: 0.5.14 + lz-string: 1.4.4 + pretty-format: 27.5.1 + + '@testing-library/react@13.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@babel/runtime': 7.18.9 + '@testing-library/dom': 8.17.1 + '@types/react-dom': 18.0.6 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + + '@tootallnate/once@2.0.0': {} + + '@types/aria-query@4.2.2': {} + + '@types/aws-lambda@8.10.147': {} + + '@types/chai-subset@1.3.3': + dependencies: + '@types/chai': 4.3.4 + + '@types/chai@4.3.4': {} + + '@types/debug@4.1.7': + dependencies: + '@types/ms': 0.7.31 + + '@types/istanbul-lib-coverage@2.0.4': {} + + '@types/json-schema@7.0.11': {} + + '@types/json5@0.0.29': {} + + '@types/minimist@1.2.2': {} + + '@types/ms@0.7.31': {} + + '@types/node@12.20.55': {} + + '@types/node@18.7.15': {} + + '@types/normalize-package-data@2.4.1': {} + + '@types/prop-types@15.7.5': {} + + '@types/react-dom@18.0.6': + dependencies: + '@types/react': 18.0.21 + + '@types/react@18.0.21': + dependencies: + '@types/prop-types': 15.7.5 + '@types/scheduler': 0.16.2 + csstype: 3.1.0 + + '@types/scheduler@0.16.2': {} + + '@types/semver@7.5.0': {} + + '@types/uuid@8.3.4': {} + + '@typescript-eslint/eslint-plugin@5.36.1(@typescript-eslint/parser@7.1.1(eslint@8.23.0)(typescript@5.4.2))(eslint@8.23.0)(typescript@5.4.2)': + dependencies: + '@typescript-eslint/parser': 7.1.1(eslint@8.23.0)(typescript@5.4.2) + '@typescript-eslint/scope-manager': 5.36.1 + '@typescript-eslint/type-utils': 5.36.1(eslint@8.23.0)(typescript@5.4.2) + '@typescript-eslint/utils': 5.36.1(eslint@8.23.0)(typescript@5.4.2) + debug: 4.3.4 + eslint: 8.23.0 + functional-red-black-tree: 1.0.1 + ignore: 5.2.0 + regexpp: 3.2.0 + semver: 7.5.4 + tsutils: 3.21.0(typescript@5.4.2) + optionalDependencies: + typescript: 5.4.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@7.1.1(eslint@8.23.0)(typescript@5.4.2)': + dependencies: + '@typescript-eslint/scope-manager': 7.1.1 + '@typescript-eslint/types': 7.1.1 + '@typescript-eslint/typescript-estree': 7.1.1(typescript@5.4.2) + '@typescript-eslint/visitor-keys': 7.1.1 + debug: 4.3.4 + eslint: 8.23.0 + optionalDependencies: + typescript: 5.4.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@5.36.1': + dependencies: + '@typescript-eslint/types': 5.36.1 + '@typescript-eslint/visitor-keys': 5.36.1 + + '@typescript-eslint/scope-manager@7.1.1': + dependencies: + '@typescript-eslint/types': 7.1.1 + '@typescript-eslint/visitor-keys': 7.1.1 + + '@typescript-eslint/type-utils@5.36.1(eslint@8.23.0)(typescript@5.4.2)': + dependencies: + '@typescript-eslint/typescript-estree': 5.36.1(typescript@5.4.2) + '@typescript-eslint/utils': 5.36.1(eslint@8.23.0)(typescript@5.4.2) + debug: 4.3.4 + eslint: 8.23.0 + tsutils: 3.21.0(typescript@5.4.2) + optionalDependencies: + typescript: 5.4.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@5.36.1': {} + + '@typescript-eslint/types@7.1.1': {} + + '@typescript-eslint/typescript-estree@5.36.1(typescript@5.4.2)': + dependencies: + '@typescript-eslint/types': 5.36.1 + '@typescript-eslint/visitor-keys': 5.36.1 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.5.4 + tsutils: 3.21.0(typescript@5.4.2) + optionalDependencies: + typescript: 5.4.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/typescript-estree@7.1.1(typescript@5.4.2)': + dependencies: + '@typescript-eslint/types': 7.1.1 + '@typescript-eslint/visitor-keys': 7.1.1 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + minimatch: 9.0.3 + semver: 7.6.0 + ts-api-utils: 1.2.1(typescript@5.4.2) + optionalDependencies: + typescript: 5.4.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@5.36.1(eslint@8.23.0)(typescript@5.4.2)': + dependencies: + '@types/json-schema': 7.0.11 + '@typescript-eslint/scope-manager': 5.36.1 + '@typescript-eslint/types': 5.36.1 + '@typescript-eslint/typescript-estree': 5.36.1(typescript@5.4.2) + eslint: 8.23.0 + eslint-scope: 5.1.1 + eslint-utils: 3.0.0(eslint@8.23.0) + transitivePeerDependencies: + - supports-color + - typescript + + '@typescript-eslint/visitor-keys@5.36.1': + dependencies: + '@typescript-eslint/types': 5.36.1 + eslint-visitor-keys: 3.3.0 + + '@typescript-eslint/visitor-keys@7.1.1': + dependencies: + '@typescript-eslint/types': 7.1.1 + eslint-visitor-keys: 3.4.3 + + '@upstash/redis@1.24.3': + dependencies: + crypto-js: 4.2.0 + + '@vercel/kv@1.0.0': + dependencies: + '@upstash/redis': 1.24.3 + + '@vitejs/plugin-react@3.0.1(vite@4.0.5(@types/node@18.7.15))': + dependencies: + '@babel/core': 7.20.12 + '@babel/plugin-transform-react-jsx-self': 7.18.6(@babel/core@7.20.12) + '@babel/plugin-transform-react-jsx-source': 7.19.6(@babel/core@7.20.12) + magic-string: 0.27.0 + react-refresh: 0.14.0 + vite: 4.0.5(@types/node@18.7.15) + transitivePeerDependencies: + - supports-color + + '@vitest/coverage-c8@0.27.2(jsdom@20.0.3)': + dependencies: + c8: 7.12.0 + vitest: 0.27.2(jsdom@20.0.3) + transitivePeerDependencies: + - '@edge-runtime/vm' + - '@vitest/browser' + - '@vitest/ui' + - happy-dom + - jsdom + - less + - sass + - stylus + - sugarss + - supports-color + - terser + + '@vitest/expect@0.28.1': + dependencies: + '@vitest/spy': 0.28.1 + '@vitest/utils': 0.28.1 + chai: 4.3.7 + + '@vitest/runner@0.28.1': + dependencies: + '@vitest/utils': 0.28.1 + p-limit: 4.0.0 + pathe: 1.1.0 + + '@vitest/spy@0.28.1': + dependencies: + tinyspy: 1.0.2 + + '@vitest/utils@0.28.1': + dependencies: + cli-truncate: 3.1.0 + diff: 5.1.0 + loupe: 2.3.6 + picocolors: 1.0.0 + pretty-format: 27.5.1 + + abab@2.0.6: {} + + accepts@1.3.8: + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + + acorn-globals@7.0.1: + dependencies: + acorn: 8.8.1 + acorn-walk: 8.2.0 + + acorn-jsx@5.3.2(acorn@8.8.1): + dependencies: + acorn: 8.8.1 + + acorn-walk@8.2.0: {} + + acorn@8.8.1: {} + + agent-base@6.0.2: + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + + aggregate-error@3.1.0: + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-colors@4.1.3: {} + + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + + ansi-regex@5.0.1: {} + + ansi-regex@6.0.1: {} + + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@5.2.0: {} + + ansi-styles@6.1.0: {} + + any-promise@1.3.0: {} + + anymatch@3.1.2: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + argparse@2.0.1: {} + + aria-query@4.2.2: + dependencies: + '@babel/runtime': 7.18.9 + '@babel/runtime-corejs3': 7.18.9 + + aria-query@5.0.2: {} + + array-includes@3.1.5: + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.2 + get-intrinsic: 1.1.2 + is-string: 1.0.7 + + array-union@2.1.0: {} + + array.prototype.flat@1.3.0: + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.2 + es-shim-unscopables: 1.0.0 + + array.prototype.flatmap@1.3.0: + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.2 + es-shim-unscopables: 1.0.0 + + arrify@1.0.1: {} + + assertion-error@1.1.0: {} + + ast-types-flow@0.0.7: {} + + astral-regex@2.0.0: {} + + asynckit@0.4.0: {} + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.0.0 + + aws-lambda@1.0.7: + dependencies: + aws-sdk: 2.1692.0 + commander: 3.0.2 + js-yaml: 3.14.1 + watchpack: 2.4.2 + + aws-sdk@2.1692.0: + dependencies: + buffer: 4.9.2 + events: 1.1.1 + ieee754: 1.1.13 + jmespath: 0.16.0 + querystring: 0.2.0 + sax: 1.2.1 + url: 0.10.3 + util: 0.12.5 + uuid: 8.0.0 + xml2js: 0.6.2 + + axe-core@4.4.3: {} + + axobject-query@2.2.0: {} + + balanced-match@1.0.2: {} + + base64-js@1.5.1: {} + + better-path-resolve@1.0.0: + dependencies: + is-windows: 1.0.2 + + binary-extensions@2.2.0: {} + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.2: + dependencies: + fill-range: 7.0.1 + + breakword@1.0.5: + dependencies: + wcwidth: 1.0.1 + + browserslist@4.21.3: + dependencies: + caniuse-lite: 1.0.30001390 + electron-to-chromium: 1.4.241 + node-releases: 2.0.6 + update-browserslist-db: 1.0.7(browserslist@4.21.3) + + buffer-from@1.1.2: {} + + buffer@4.9.2: + dependencies: + base64-js: 1.5.1 + ieee754: 1.1.13 + isarray: 1.0.0 + + bundle-require@3.1.0(esbuild@0.15.7): + dependencies: + esbuild: 0.15.7 + load-tsconfig: 0.2.3 + + busboy@1.6.0: + dependencies: + streamsearch: 1.1.0 + + bytes@3.1.2: {} + + c8@7.12.0: + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@istanbuljs/schema': 0.1.3 + find-up: 5.0.0 + foreground-child: 2.0.0 + istanbul-lib-coverage: 3.2.0 + istanbul-lib-report: 3.0.0 + istanbul-reports: 3.1.5 + rimraf: 3.0.2 + test-exclude: 6.0.0 + v8-to-istanbul: 9.0.1 + yargs: 16.2.0 + yargs-parser: 20.2.9 + + cac@6.7.14: {} + + call-bind-apply-helpers@1.0.1: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.2: + dependencies: + function-bind: 1.1.1 + get-intrinsic: 1.1.2 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.1 + es-define-property: 1.0.1 + get-intrinsic: 1.2.7 + set-function-length: 1.2.2 + + call-bound@1.0.3: + dependencies: + call-bind-apply-helpers: 1.0.1 + get-intrinsic: 1.2.7 + + callsites@3.1.0: {} + + camelcase-keys@6.2.2: + dependencies: + camelcase: 5.3.1 + map-obj: 4.3.0 + quick-lru: 4.0.1 + + camelcase@5.3.1: {} + + caniuse-lite@1.0.30001390: {} + + chai@4.3.7: + dependencies: + assertion-error: 1.1.0 + check-error: 1.0.2 + deep-eql: 4.1.3 + get-func-name: 2.0.0 + loupe: 2.3.4 + pathval: 1.1.1 + type-detect: 4.0.8 + + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chardet@0.7.0: {} + + check-error@1.0.2: {} + + chokidar@3.5.3: + dependencies: + anymatch: 3.1.2 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + ci-info@3.9.0: {} + + clean-publish@4.0.1: + dependencies: + cross-spawn: 7.0.3 + fast-glob: 3.2.11 + lilconfig: 2.0.6 + micromatch: 4.0.5 + + clean-stack@2.2.0: {} + + cli-cursor@3.1.0: + dependencies: + restore-cursor: 3.1.0 + + cli-truncate@2.1.0: + dependencies: + slice-ansi: 3.0.0 + string-width: 4.2.3 + + cli-truncate@3.1.0: + dependencies: + slice-ansi: 5.0.0 + string-width: 5.1.2 + + cliui@6.0.0: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + + cliui@7.0.4: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + clone@1.0.4: {} + + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.3: {} + + color-name@1.1.4: {} + + colorette@2.0.19: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@3.0.2: {} + + commander@4.1.1: {} + + commander@9.4.1: {} + + concat-map@0.0.1: {} + + confusing-browser-globals@1.0.11: {} + + content-disposition@0.5.4: + dependencies: + safe-buffer: 5.2.1 + + convert-source-map@1.8.0: + dependencies: + safe-buffer: 5.1.2 + + core-js-pure@3.25.0: {} + + cross-spawn@5.1.0: + dependencies: + lru-cache: 4.1.5 + shebang-command: 1.2.0 + which: 1.3.1 + + cross-spawn@7.0.3: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + crypto-js@4.2.0: {} + + cssom@0.3.8: {} + + cssom@0.5.0: {} + + cssstyle@2.3.0: + dependencies: + cssom: 0.3.8 + + csstype@3.1.0: {} + + csv-generate@3.4.3: {} + + csv-parse@4.16.3: {} + + csv-stringify@5.6.5: {} + + csv@5.5.3: + dependencies: + csv-generate: 3.4.3 + csv-parse: 4.16.3 + csv-stringify: 5.6.5 + stream-transform: 2.1.3 + + damerau-levenshtein@1.0.8: {} + + data-urls@3.0.2: + dependencies: + abab: 2.0.6 + whatwg-mimetype: 3.0.0 + whatwg-url: 11.0.0 + + debug@2.6.9: + dependencies: + ms: 2.0.0 + + debug@3.2.7: + dependencies: + ms: 2.1.3 + + debug@4.3.4: + dependencies: + ms: 2.1.2 + + decamelize-keys@1.1.1: + dependencies: + decamelize: 1.2.0 + map-obj: 1.0.1 + + decamelize@1.2.0: {} + + decimal.js@10.4.3: {} + + decode-uri-component@0.2.2: {} + + deep-eql@4.1.3: + dependencies: + type-detect: 4.0.8 + + deep-is@0.1.4: {} + + defaults@1.0.3: + dependencies: + clone: 1.0.4 + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-lazy-prop@2.0.0: {} + + define-properties@1.1.4: + dependencies: + has-property-descriptors: 1.0.0 + object-keys: 1.1.1 + + delayed-stream@1.0.0: {} + + depd@1.1.2: {} + + depd@2.0.0: {} + + detect-indent@6.1.0: {} + + diff@5.1.0: {} + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + + doctrine@3.0.0: + dependencies: + esutils: 2.0.3 + + dom-accessibility-api@0.5.14: {} + + domexception@4.0.0: + dependencies: + webidl-conversions: 7.0.0 + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + eastasianwidth@0.2.0: {} + + electron-to-chromium@1.4.241: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + enhanced-resolve@5.10.0: + dependencies: + graceful-fs: 4.2.10 + tapable: 2.2.1 + + enquirer@2.3.6: + dependencies: + ansi-colors: 4.1.3 + + entities@4.4.0: {} + + error-ex@1.3.2: + dependencies: + is-arrayish: 0.2.1 + + es-abstract@1.20.2: + dependencies: + call-bind: 1.0.2 + es-to-primitive: 1.2.1 + function-bind: 1.1.1 + function.prototype.name: 1.1.5 + get-intrinsic: 1.1.2 + get-symbol-description: 1.0.0 + has: 1.0.3 + has-property-descriptors: 1.0.0 + has-symbols: 1.0.3 + internal-slot: 1.0.3 + is-callable: 1.2.4 + is-negative-zero: 2.0.2 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.2 + is-string: 1.0.7 + is-weakref: 1.0.2 + object-inspect: 1.12.2 + object-keys: 1.1.1 + object.assign: 4.1.4 + regexp.prototype.flags: 1.4.3 + string.prototype.trimend: 1.0.5 + string.prototype.trimstart: 1.0.5 + unbox-primitive: 1.0.2 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-shim-unscopables@1.0.0: + dependencies: + has: 1.0.3 + + es-to-primitive@1.2.1: + dependencies: + is-callable: 1.2.4 + is-date-object: 1.0.5 + is-symbol: 1.0.4 + + esbuild-android-64@0.14.54: optional: true - /esbuild-sunos-64@0.14.54: - resolution: {integrity: sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true + esbuild-android-64@0.15.7: optional: true - /esbuild-sunos-64@0.15.7: - resolution: {integrity: sha512-8CDI1aL/ts0mDGbWzjEOGKXnU7p3rDzggHSBtVryQzkSOsjCHRVe0iFYUuhczlxU1R3LN/E7HgUO4NXzGGP/Ag==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true + esbuild-android-arm64@0.14.54: optional: true - /esbuild-windows-32@0.14.54: - resolution: {integrity: sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true + esbuild-android-arm64@0.15.7: optional: true - /esbuild-windows-32@0.15.7: - resolution: {integrity: sha512-cOnKXUEPS8EGCzRSFa1x6NQjGhGsFlVgjhqGEbLTPsA7x4RRYiy2RKoArNUU4iR2vHmzqS5Gr84MEumO/wxYKA==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true + esbuild-darwin-64@0.14.54: optional: true - /esbuild-windows-64@0.14.54: - resolution: {integrity: sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true + esbuild-darwin-64@0.15.7: optional: true - /esbuild-windows-64@0.15.7: - resolution: {integrity: sha512-7MI08Ec2sTIDv+zH6StNBKO+2hGUYIT42GmFyW6MBBWWtJhTcQLinKS6ldIN1d52MXIbiJ6nXyCJ+LpL4jBm3Q==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true + esbuild-darwin-arm64@0.14.54: optional: true - /esbuild-windows-arm64@0.14.54: - resolution: {integrity: sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true + esbuild-darwin-arm64@0.15.7: optional: true - /esbuild-windows-arm64@0.15.7: - resolution: {integrity: sha512-R06nmqBlWjKHddhRJYlqDd3Fabx9LFdKcjoOy08YLimwmsswlFBJV4rXzZCxz/b7ZJXvrZgj8DDv1ewE9+StMw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true + esbuild-freebsd-64@0.14.54: optional: true - /esbuild@0.14.54: - resolution: {integrity: sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==} - engines: {node: '>=12'} - hasBin: true - requiresBuild: true + esbuild-freebsd-64@0.15.7: + optional: true + + esbuild-freebsd-arm64@0.14.54: + optional: true + + esbuild-freebsd-arm64@0.15.7: + optional: true + + esbuild-linux-32@0.14.54: + optional: true + + esbuild-linux-32@0.15.7: + optional: true + + esbuild-linux-64@0.14.54: + optional: true + + esbuild-linux-64@0.15.7: + optional: true + + esbuild-linux-arm64@0.14.54: + optional: true + + esbuild-linux-arm64@0.15.7: + optional: true + + esbuild-linux-arm@0.14.54: + optional: true + + esbuild-linux-arm@0.15.7: + optional: true + + esbuild-linux-mips64le@0.14.54: + optional: true + + esbuild-linux-mips64le@0.15.7: + optional: true + + esbuild-linux-ppc64le@0.14.54: + optional: true + + esbuild-linux-ppc64le@0.15.7: + optional: true + + esbuild-linux-riscv64@0.14.54: + optional: true + + esbuild-linux-riscv64@0.15.7: + optional: true + + esbuild-linux-s390x@0.14.54: + optional: true + + esbuild-linux-s390x@0.15.7: + optional: true + + esbuild-netbsd-64@0.14.54: + optional: true + + esbuild-netbsd-64@0.15.7: + optional: true + + esbuild-openbsd-64@0.14.54: + optional: true + + esbuild-openbsd-64@0.15.7: + optional: true + + esbuild-sunos-64@0.14.54: + optional: true + + esbuild-sunos-64@0.15.7: + optional: true + + esbuild-windows-32@0.14.54: + optional: true + + esbuild-windows-32@0.15.7: + optional: true + + esbuild-windows-64@0.14.54: + optional: true + + esbuild-windows-64@0.15.7: + optional: true + + esbuild-windows-arm64@0.14.54: + optional: true + + esbuild-windows-arm64@0.15.7: + optional: true + + esbuild@0.14.54: optionalDependencies: '@esbuild/linux-loong64': 0.14.54 esbuild-android-64: 0.14.54 @@ -2801,13 +5118,8 @@ packages: esbuild-windows-32: 0.14.54 esbuild-windows-64: 0.14.54 esbuild-windows-arm64: 0.14.54 - dev: true - /esbuild@0.15.7: - resolution: {integrity: sha512-7V8tzllIbAQV1M4QoE52ImKu8hT/NLGlGXkiDsbEU5PS6K8Mn09ZnYoS+dcmHxOS9CRsV4IRAMdT3I67IyUNXw==} - engines: {node: '>=12'} - hasBin: true - requiresBuild: true + esbuild@0.15.7: optionalDependencies: '@esbuild/linux-loong64': 0.15.7 esbuild-android-64: 0.15.7 @@ -2830,13 +5142,8 @@ packages: esbuild-windows-32: 0.15.7 esbuild-windows-64: 0.15.7 esbuild-windows-arm64: 0.15.7 - dev: true - /esbuild@0.16.17: - resolution: {integrity: sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==} - engines: {node: '>=12'} - hasBin: true - requiresBuild: true + esbuild@0.16.17: optionalDependencies: '@esbuild/android-arm': 0.16.17 '@esbuild/android-arm64': 0.16.17 @@ -2860,27 +5167,14 @@ packages: '@esbuild/win32-arm64': 0.16.17 '@esbuild/win32-ia32': 0.16.17 '@esbuild/win32-x64': 0.16.17 - dev: true - /escalade@3.1.1: - resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} - engines: {node: '>=6'} - dev: true + escalade@3.1.1: {} - /escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - dev: true + escape-string-regexp@1.0.5: {} - /escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - dev: true + escape-string-regexp@4.0.0: {} - /escodegen@2.0.0: - resolution: {integrity: sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==} - engines: {node: '>=6.0'} - hasBin: true + escodegen@2.0.0: dependencies: esprima: 4.0.1 estraverse: 5.3.0 @@ -2888,144 +5182,80 @@ packages: optionator: 0.8.3 optionalDependencies: source-map: 0.6.1 - dev: true - /eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.26.0)(eslint@8.23.0): - resolution: {integrity: sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==} - engines: {node: ^10.12.0 || >=12.0.0} - peerDependencies: - eslint: ^7.32.0 || ^8.2.0 - eslint-plugin-import: ^2.25.2 + eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.26.0)(eslint@8.23.0): dependencies: confusing-browser-globals: 1.0.11 eslint: 8.23.0 - eslint-plugin-import: 2.26.0(@typescript-eslint/parser@7.1.1)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0) + eslint-plugin-import: 2.26.0(@typescript-eslint/parser@7.1.1(eslint@8.23.0)(typescript@5.4.2))(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0) object.assign: 4.1.4 object.entries: 1.1.5 semver: 6.3.0 - dev: true - /eslint-config-airbnb-typescript@17.1.0(@typescript-eslint/eslint-plugin@5.36.1)(@typescript-eslint/parser@7.1.1)(eslint-plugin-import@2.26.0)(eslint@8.23.0): - resolution: {integrity: sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig==} - peerDependencies: - '@typescript-eslint/eslint-plugin': ^5.13.0 || ^6.0.0 - '@typescript-eslint/parser': ^5.0.0 || ^6.0.0 - eslint: ^7.32.0 || ^8.2.0 - eslint-plugin-import: ^2.25.3 + eslint-config-airbnb-typescript@17.1.0(@typescript-eslint/eslint-plugin@5.36.1(@typescript-eslint/parser@7.1.1(eslint@8.23.0)(typescript@5.4.2))(eslint@8.23.0)(typescript@5.4.2))(@typescript-eslint/parser@7.1.1(eslint@8.23.0)(typescript@5.4.2))(eslint-plugin-import@2.26.0)(eslint@8.23.0): dependencies: - '@typescript-eslint/eslint-plugin': 5.36.1(@typescript-eslint/parser@7.1.1)(eslint@8.23.0)(typescript@5.4.2) + '@typescript-eslint/eslint-plugin': 5.36.1(@typescript-eslint/parser@7.1.1(eslint@8.23.0)(typescript@5.4.2))(eslint@8.23.0)(typescript@5.4.2) '@typescript-eslint/parser': 7.1.1(eslint@8.23.0)(typescript@5.4.2) eslint: 8.23.0 eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.26.0)(eslint@8.23.0) - eslint-plugin-import: 2.26.0(@typescript-eslint/parser@7.1.1)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0) - dev: true + eslint-plugin-import: 2.26.0(@typescript-eslint/parser@7.1.1(eslint@8.23.0)(typescript@5.4.2))(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0) - /eslint-config-airbnb@19.0.4(eslint-plugin-import@2.26.0)(eslint-plugin-jsx-a11y@6.6.1)(eslint-plugin-react-hooks@4.6.0)(eslint-plugin-react@7.31.6)(eslint@8.23.0): - resolution: {integrity: sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==} - engines: {node: ^10.12.0 || ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^7.32.0 || ^8.2.0 - eslint-plugin-import: ^2.25.3 - eslint-plugin-jsx-a11y: ^6.5.1 - eslint-plugin-react: ^7.28.0 - eslint-plugin-react-hooks: ^4.3.0 + eslint-config-airbnb@19.0.4(eslint-plugin-import@2.26.0)(eslint-plugin-jsx-a11y@6.6.1(eslint@8.23.0))(eslint-plugin-react-hooks@4.6.0(eslint@8.23.0))(eslint-plugin-react@7.31.6(eslint@8.23.0))(eslint@8.23.0): dependencies: eslint: 8.23.0 eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.26.0)(eslint@8.23.0) - eslint-plugin-import: 2.26.0(@typescript-eslint/parser@7.1.1)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0) + eslint-plugin-import: 2.26.0(@typescript-eslint/parser@7.1.1(eslint@8.23.0)(typescript@5.4.2))(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0) eslint-plugin-jsx-a11y: 6.6.1(eslint@8.23.0) eslint-plugin-react: 7.31.6(eslint@8.23.0) eslint-plugin-react-hooks: 4.6.0(eslint@8.23.0) object.assign: 4.1.4 object.entries: 1.1.5 - dev: true - /eslint-config-prettier@8.5.0(eslint@8.23.0): - resolution: {integrity: sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==} - hasBin: true - peerDependencies: - eslint: '>=7.0.0' + eslint-config-prettier@8.5.0(eslint@8.23.0): dependencies: eslint: 8.23.0 - dev: true - /eslint-import-resolver-node@0.3.6: - resolution: {integrity: sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==} + eslint-import-resolver-node@0.3.6: dependencies: debug: 3.2.7 resolve: 1.22.1 transitivePeerDependencies: - supports-color - dev: true - /eslint-import-resolver-typescript@3.5.0(eslint-plugin-import@2.26.0)(eslint@8.23.0): - resolution: {integrity: sha512-DEfpfuk+O/T5e9HBZOxocmwMuUGkvQQd5WRiMJF9kKNT9amByqOyGlWoAZAQiv0SZSy4GMtG1clmnvQA/RzA0A==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - peerDependencies: - eslint: '*' - eslint-plugin-import: '*' + eslint-import-resolver-typescript@3.5.0(eslint-plugin-import@2.26.0)(eslint@8.23.0): dependencies: - debug: 4.3.4 - enhanced-resolve: 5.10.0 - eslint: 8.23.0 - eslint-plugin-import: 2.26.0(@typescript-eslint/parser@7.1.1)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0) - get-tsconfig: 4.2.0 - globby: 13.1.2 - is-core-module: 2.10.0 - is-glob: 4.0.3 - synckit: 0.8.4 - transitivePeerDependencies: - - supports-color - dev: true - - /eslint-module-utils@2.7.4(@typescript-eslint/parser@7.1.1)(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0): - resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true + debug: 4.3.4 + enhanced-resolve: 5.10.0 + eslint: 8.23.0 + eslint-plugin-import: 2.26.0(@typescript-eslint/parser@7.1.1(eslint@8.23.0)(typescript@5.4.2))(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0) + get-tsconfig: 4.2.0 + globby: 13.1.2 + is-core-module: 2.10.0 + is-glob: 4.0.3 + synckit: 0.8.4 + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.7.4(@typescript-eslint/parser@7.1.1(eslint@8.23.0)(typescript@5.4.2))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0): dependencies: - '@typescript-eslint/parser': 7.1.1(eslint@8.23.0)(typescript@5.4.2) debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 7.1.1(eslint@8.23.0)(typescript@5.4.2) eslint: 8.23.0 eslint-import-resolver-node: 0.3.6 eslint-import-resolver-typescript: 3.5.0(eslint-plugin-import@2.26.0)(eslint@8.23.0) transitivePeerDependencies: - supports-color - dev: true - /eslint-plugin-import@2.26.0(@typescript-eslint/parser@7.1.1)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0): - resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true + eslint-plugin-import@2.26.0(@typescript-eslint/parser@7.1.1(eslint@8.23.0)(typescript@5.4.2))(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0): dependencies: - '@typescript-eslint/parser': 7.1.1(eslint@8.23.0)(typescript@5.4.2) array-includes: 3.1.5 array.prototype.flat: 1.3.0 debug: 2.6.9 doctrine: 2.1.0 eslint: 8.23.0 eslint-import-resolver-node: 0.3.6 - eslint-module-utils: 2.7.4(@typescript-eslint/parser@7.1.1)(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0) + eslint-module-utils: 2.7.4(@typescript-eslint/parser@7.1.1(eslint@8.23.0)(typescript@5.4.2))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.5.0)(eslint@8.23.0) has: 1.0.3 is-core-module: 2.10.0 is-glob: 4.0.3 @@ -3033,17 +5263,14 @@ packages: object.values: 1.1.5 resolve: 1.22.1 tsconfig-paths: 3.14.1 + optionalDependencies: + '@typescript-eslint/parser': 7.1.1(eslint@8.23.0)(typescript@5.4.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - dev: true - /eslint-plugin-jsx-a11y@6.6.1(eslint@8.23.0): - resolution: {integrity: sha512-sXgFVNHiWffBq23uiS/JaP6eVR622DqwB4yTzKvGZGcPq6/yZ3WmOZfuBks/vHWo9GaFOqC2ZK4i6+C35knx7Q==} - engines: {node: '>=4.0'} - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + eslint-plugin-jsx-a11y@6.6.1(eslint@8.23.0): dependencies: '@babel/runtime': 7.18.9 aria-query: 4.2.2 @@ -3059,22 +5286,12 @@ packages: language-tags: 1.0.5 minimatch: 3.1.2 semver: 6.3.0 - dev: true - /eslint-plugin-react-hooks@4.6.0(eslint@8.23.0): - resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} - engines: {node: '>=10'} - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + eslint-plugin-react-hooks@4.6.0(eslint@8.23.0): dependencies: eslint: 8.23.0 - dev: true - /eslint-plugin-react@7.31.6(eslint@8.23.0): - resolution: {integrity: sha512-CXu4eu28sb8Sd2+cyUYsJVyDvpTlaXPG+bOzzpS9IzZKtye96AYX3ZmHQ6ayn/OAIQ/ufDJP8ElPWd63Pepn9w==} - engines: {node: '>=4'} - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + eslint-plugin-react@7.31.6(eslint@8.23.0): dependencies: array-includes: 3.1.5 array.prototype.flatmap: 1.3.0 @@ -3091,61 +5308,33 @@ packages: resolve: 2.0.0-next.4 semver: 6.3.0 string.prototype.matchall: 4.0.7 - dev: true - /eslint-plugin-simple-import-sort@8.0.0(eslint@8.23.0): - resolution: {integrity: sha512-bXgJQ+lqhtQBCuWY/FUWdB27j4+lqcvXv5rUARkzbeWLwea+S5eBZEQrhnO+WgX3ZoJHVj0cn943iyXwByHHQw==} - peerDependencies: - eslint: '>=5.0.0' + eslint-plugin-simple-import-sort@8.0.0(eslint@8.23.0): dependencies: eslint: 8.23.0 - dev: true - /eslint-scope@5.1.1: - resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} - engines: {node: '>=8.0.0'} + eslint-scope@5.1.1: dependencies: esrecurse: 4.3.0 estraverse: 4.3.0 - dev: true - /eslint-scope@7.1.1: - resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-scope@7.1.1: dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 - dev: true - /eslint-utils@3.0.0(eslint@8.23.0): - resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} - engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} - peerDependencies: - eslint: '>=5' + eslint-utils@3.0.0(eslint@8.23.0): dependencies: eslint: 8.23.0 eslint-visitor-keys: 2.1.0 - dev: true - /eslint-visitor-keys@2.1.0: - resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} - engines: {node: '>=10'} - dev: true + eslint-visitor-keys@2.1.0: {} - /eslint-visitor-keys@3.3.0: - resolution: {integrity: sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true + eslint-visitor-keys@3.3.0: {} - /eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true + eslint-visitor-keys@3.4.3: {} - /eslint@8.23.0: - resolution: {integrity: sha512-pBG/XOn0MsJcKcTRLr27S5HpzQo4kLr+HjLQIyK4EiCsijDl/TB+h5uEuJU6bQ8Edvwz1XWOjpaP2qgnXGpTcA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - hasBin: true + eslint@8.23.0: dependencies: '@eslint/eslintrc': 1.3.1 '@humanwhocodes/config-array': 0.10.4 @@ -3188,60 +5377,32 @@ packages: text-table: 0.2.0 transitivePeerDependencies: - supports-color - dev: true - /espree@9.4.0: - resolution: {integrity: sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + espree@9.4.0: dependencies: acorn: 8.8.1 acorn-jsx: 5.3.2(acorn@8.8.1) eslint-visitor-keys: 3.3.0 - dev: true - /esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - dev: true + esprima@4.0.1: {} - /esquery@1.4.0: - resolution: {integrity: sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==} - engines: {node: '>=0.10'} + esquery@1.4.0: dependencies: estraverse: 5.3.0 - dev: true - /esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} + esrecurse@4.3.0: dependencies: estraverse: 5.3.0 - dev: true - /estraverse@4.3.0: - resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} - engines: {node: '>=4.0'} - dev: true + estraverse@4.3.0: {} - /estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - dev: true + estraverse@5.3.0: {} - /esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - dev: true + esutils@2.0.3: {} - /events@1.1.1: - resolution: {integrity: sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==} - engines: {node: '>=0.4.x'} - dev: true + events@1.1.1: {} - /execa@5.1.1: - resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} - engines: {node: '>=10'} + execa@5.1.1: dependencies: cross-spawn: 7.0.3 get-stream: 6.0.1 @@ -3252,11 +5413,8 @@ packages: onetime: 5.1.2 signal-exit: 3.0.7 strip-final-newline: 2.0.0 - dev: true - /execa@6.1.0: - resolution: {integrity: sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + execa@6.1.0: dependencies: cross-spawn: 7.0.3 get-stream: 6.0.1 @@ -3267,213 +5425,127 @@ packages: onetime: 6.0.0 signal-exit: 3.0.7 strip-final-newline: 3.0.0 - dev: true - /extendable-error@0.1.7: - resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} - dev: true + extendable-error@0.1.7: {} - /external-editor@3.1.0: - resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} - engines: {node: '>=4'} + external-editor@3.1.0: dependencies: chardet: 0.7.0 iconv-lite: 0.4.24 tmp: 0.0.33 - dev: true - /fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: true + fast-deep-equal@3.1.3: {} - /fast-glob@3.2.11: - resolution: {integrity: sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==} - engines: {node: '>=8.6.0'} + fast-glob@3.2.11: dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 micromatch: 4.0.5 - dev: true - /fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - dev: true + fast-json-stable-stringify@2.1.0: {} - /fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - dev: true + fast-levenshtein@2.0.6: {} - /fastq@1.13.0: - resolution: {integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==} + fastq@1.13.0: dependencies: reusify: 1.0.4 - dev: true - /file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} + file-entry-cache@6.0.1: dependencies: flat-cache: 3.0.4 - dev: true - /fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} - engines: {node: '>=8'} + fill-range@7.0.1: dependencies: to-regex-range: 5.0.1 - dev: true - /filter-obj@1.1.0: - resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==} - engines: {node: '>=0.10.0'} - dev: true + filter-obj@1.1.0: {} - /find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} + find-up@4.1.0: dependencies: locate-path: 5.0.0 path-exists: 4.0.0 - dev: true - /find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} + find-up@5.0.0: dependencies: locate-path: 6.0.0 path-exists: 4.0.0 - dev: true - /find-yarn-workspace-root2@1.2.16: - resolution: {integrity: sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA==} + find-yarn-workspace-root2@1.2.16: dependencies: micromatch: 4.0.5 pkg-dir: 4.2.0 - dev: true - /flat-cache@3.0.4: - resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} - engines: {node: ^10.12.0 || >=12.0.0} + flat-cache@3.0.4: dependencies: flatted: 3.2.7 rimraf: 3.0.2 - dev: true - /flatted@3.2.7: - resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} - dev: true + flatted@3.2.7: {} - /for-each@0.3.3: - resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + for-each@0.3.3: dependencies: is-callable: 1.2.4 - dev: true - /foreground-child@2.0.0: - resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==} - engines: {node: '>=8.0.0'} + foreground-child@2.0.0: dependencies: cross-spawn: 7.0.3 signal-exit: 3.0.7 - dev: true - /form-data@4.0.0: - resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} - engines: {node: '>= 6'} + form-data@4.0.0: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 mime-types: 2.1.35 - dev: true - /fresh@0.5.2: - resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} - engines: {node: '>= 0.6'} - dev: true + fresh@0.5.2: {} - /fs-extra@7.0.1: - resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} - engines: {node: '>=6 <7 || >=8'} + fs-extra@7.0.1: dependencies: graceful-fs: 4.2.10 jsonfile: 4.0.0 universalify: 0.1.2 - dev: true - /fs-extra@8.1.0: - resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} - engines: {node: '>=6 <7 || >=8'} + fs-extra@8.1.0: dependencies: graceful-fs: 4.2.10 jsonfile: 4.0.0 universalify: 0.1.2 - dev: true - /fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - dev: true + fs.realpath@1.0.0: {} - /fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true - dev: true + fsevents@2.3.3: optional: true - /function-bind@1.1.1: - resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} - dev: true + function-bind@1.1.1: {} - /function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - dev: true + function-bind@1.1.2: {} - /function.prototype.name@1.1.5: - resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} - engines: {node: '>= 0.4'} + function.prototype.name@1.1.5: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 es-abstract: 1.20.2 functions-have-names: 1.2.3 - dev: true - /functional-red-black-tree@1.0.1: - resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} - dev: true + functional-red-black-tree@1.0.1: {} - /functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - dev: true + functions-have-names@1.2.3: {} - /gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - dev: true + gensync@1.0.0-beta.2: {} - /get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - dev: true + get-caller-file@2.0.5: {} - /get-func-name@2.0.0: - resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} - dev: true + get-func-name@2.0.0: {} - /get-intrinsic@1.1.2: - resolution: {integrity: sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==} + get-intrinsic@1.1.2: dependencies: function-bind: 1.1.1 has: 1.0.3 has-symbols: 1.0.3 - dev: true - /get-intrinsic@1.2.7: - resolution: {integrity: sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==} - engines: {node: '>= 0.4'} + get-intrinsic@1.2.7: dependencies: call-bind-apply-helpers: 1.0.1 es-define-property: 1.0.1 @@ -3485,53 +5557,32 @@ packages: has-symbols: 1.1.0 hasown: 2.0.2 math-intrinsics: 1.1.0 - dev: true - /get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} + get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 - dev: true - /get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} - dev: true + get-stream@6.0.1: {} - /get-symbol-description@1.0.0: - resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} - engines: {node: '>= 0.4'} + get-symbol-description@1.0.0: dependencies: call-bind: 1.0.2 get-intrinsic: 1.1.2 - dev: true - /get-tsconfig@4.2.0: - resolution: {integrity: sha512-X8u8fREiYOE6S8hLbq99PeykTDoLVnxvF4DjWKJmz9xy2nNRdUcV8ZN9tniJFeKyTU3qnC9lL8n4Chd6LmVKHg==} - dev: true + get-tsconfig@4.2.0: {} - /glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 - dev: true - /glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} + glob-parent@6.0.2: dependencies: is-glob: 4.0.3 - dev: true - /glob-to-regexp@0.4.1: - resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - dev: true + glob-to-regexp@0.4.1: {} - /glob@7.1.6: - resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} + glob@7.1.6: dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 @@ -3539,10 +5590,8 @@ packages: minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 - dev: true - /glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + glob@7.2.3: dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 @@ -3550,27 +5599,16 @@ packages: minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 - dev: true - /globals@11.12.0: - resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} - engines: {node: '>=4'} - dev: true + globals@11.12.0: {} - /globals@13.17.0: - resolution: {integrity: sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==} - engines: {node: '>=8'} + globals@13.17.0: dependencies: type-fest: 0.20.2 - dev: true - /globalyzer@0.1.0: - resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==} - dev: true + globalyzer@0.1.0: {} - /globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} + globby@11.1.0: dependencies: array-union: 2.1.0 dir-glob: 3.0.1 @@ -3578,502 +5616,276 @@ packages: ignore: 5.2.0 merge2: 1.4.1 slash: 3.0.0 - dev: true - /globby@13.1.2: - resolution: {integrity: sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + globby@13.1.2: dependencies: dir-glob: 3.0.1 fast-glob: 3.2.11 ignore: 5.2.0 merge2: 1.4.1 slash: 4.0.0 - dev: true - /globrex@0.1.2: - resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} - dev: true + globrex@0.1.2: {} - /gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - dev: true + gopd@1.2.0: {} - /graceful-fs@4.2.10: - resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} - dev: true + graceful-fs@4.2.10: {} - /grapheme-splitter@1.0.4: - resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} - dev: true + grapheme-splitter@1.0.4: {} - /graphql@16.8.0: - resolution: {integrity: sha512-0oKGaR+y3qcS5mCu1vb7KG+a89vjn06C7Ihq/dDl3jA+A8B3TKomvi3CiEcVLJQGalbu8F52LxkOym7U5sSfbg==} - engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} - dev: true + graphql@16.8.0: {} - /hard-rejection@2.1.0: - resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} - engines: {node: '>=6'} - dev: true + hard-rejection@2.1.0: {} - /has-bigints@1.0.2: - resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} - dev: true + has-bigints@1.0.2: {} - /has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} - dev: true + has-flag@3.0.0: {} - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - dev: true + has-flag@4.0.0: {} - /has-property-descriptors@1.0.0: - resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} + has-property-descriptors@1.0.0: dependencies: get-intrinsic: 1.1.2 - dev: true - /has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + has-property-descriptors@1.0.2: dependencies: es-define-property: 1.0.1 - dev: true - /has-symbols@1.0.3: - resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} - engines: {node: '>= 0.4'} - dev: true + has-symbols@1.0.3: {} - /has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - dev: true + has-symbols@1.1.0: {} - /has-tostringtag@1.0.0: - resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} - engines: {node: '>= 0.4'} + has-tostringtag@1.0.0: dependencies: has-symbols: 1.0.3 - dev: true - /has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} + has-tostringtag@1.0.2: dependencies: has-symbols: 1.0.3 - dev: true - /has@1.0.3: - resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} - engines: {node: '>= 0.4.0'} + has@1.0.3: dependencies: function-bind: 1.1.1 - dev: true - /hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} + hasown@2.0.2: dependencies: function-bind: 1.1.2 - dev: true - /hosted-git-info@2.8.9: - resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} - dev: true + hosted-git-info@2.8.9: {} - /html-encoding-sniffer@3.0.0: - resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==} - engines: {node: '>=12'} + html-encoding-sniffer@3.0.0: dependencies: whatwg-encoding: 2.0.0 - dev: true - /html-escaper@2.0.2: - resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - dev: true + html-escaper@2.0.2: {} - /http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} + http-errors@2.0.0: dependencies: depd: 2.0.0 inherits: 2.0.4 setprototypeof: 1.2.0 statuses: 2.0.1 toidentifier: 1.0.1 - dev: false - /http-proxy-agent@5.0.0: - resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} - engines: {node: '>= 6'} + http-proxy-agent@5.0.0: dependencies: '@tootallnate/once': 2.0.0 agent-base: 6.0.2 debug: 4.3.4 transitivePeerDependencies: - supports-color - dev: true - /https-proxy-agent@5.0.1: - resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} - engines: {node: '>= 6'} + https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 debug: 4.3.4 transitivePeerDependencies: - supports-color - dev: true - /human-id@1.0.2: - resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} - dev: true + human-id@1.0.2: {} - /human-signals@2.1.0: - resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} - engines: {node: '>=10.17.0'} - dev: true + human-signals@2.1.0: {} - /human-signals@3.0.1: - resolution: {integrity: sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==} - engines: {node: '>=12.20.0'} - dev: true + human-signals@3.0.1: {} - /husky@8.0.1: - resolution: {integrity: sha512-xs7/chUH/CKdOCs7Zy0Aev9e/dKOMZf3K1Az1nar3tzlv0jfqnYtu235bstsWTmXOR0EfINrPa97yy4Lz6RiKw==} - engines: {node: '>=14'} - hasBin: true - dev: true + husky@8.0.1: {} - /iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} - engines: {node: '>=0.10.0'} + iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 - /iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} + iconv-lite@0.6.3: dependencies: safer-buffer: 2.1.2 - dev: true - /ieee754@1.1.13: - resolution: {integrity: sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==} - dev: true + ieee754@1.1.13: {} - /ignore@5.2.0: - resolution: {integrity: sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==} - engines: {node: '>= 4'} - dev: true + ignore@5.2.0: {} - /import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} - engines: {node: '>=6'} + import-fresh@3.3.0: dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 - dev: true - /imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - dev: true + imurmurhash@0.1.4: {} - /indent-string@4.0.0: - resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} - engines: {node: '>=8'} - dev: true + indent-string@4.0.0: {} - /inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + inflight@1.0.6: dependencies: once: 1.4.0 wrappy: 1.0.2 - dev: true - /inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + inherits@2.0.4: {} - /internal-slot@1.0.3: - resolution: {integrity: sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==} - engines: {node: '>= 0.4'} + internal-slot@1.0.3: dependencies: get-intrinsic: 1.1.2 has: 1.0.3 side-channel: 1.0.4 - dev: true - /is-arguments@1.2.0: - resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} - engines: {node: '>= 0.4'} + is-arguments@1.2.0: dependencies: call-bound: 1.0.3 has-tostringtag: 1.0.2 - dev: true - /is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - dev: true + is-arrayish@0.2.1: {} - /is-bigint@1.0.4: - resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + is-bigint@1.0.4: dependencies: has-bigints: 1.0.2 - dev: true - /is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} + is-binary-path@2.1.0: dependencies: binary-extensions: 2.2.0 - dev: true - /is-boolean-object@1.1.2: - resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} - engines: {node: '>= 0.4'} + is-boolean-object@1.1.2: dependencies: call-bind: 1.0.2 has-tostringtag: 1.0.0 - dev: true - /is-callable@1.2.4: - resolution: {integrity: sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==} - engines: {node: '>= 0.4'} - dev: true + is-callable@1.2.4: {} - /is-core-module@2.10.0: - resolution: {integrity: sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==} + is-core-module@2.10.0: dependencies: has: 1.0.3 - dev: true - /is-date-object@1.0.5: - resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} - engines: {node: '>= 0.4'} + is-date-object@1.0.5: dependencies: has-tostringtag: 1.0.0 - dev: true - /is-docker@2.2.1: - resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} - engines: {node: '>=8'} - hasBin: true - dev: true + is-docker@2.2.1: {} - /is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - dev: true + is-extglob@2.1.1: {} - /is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - dev: true + is-fullwidth-code-point@3.0.0: {} - /is-fullwidth-code-point@4.0.0: - resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} - engines: {node: '>=12'} - dev: true + is-fullwidth-code-point@4.0.0: {} - /is-generator-function@1.1.0: - resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} - engines: {node: '>= 0.4'} + is-generator-function@1.1.0: dependencies: call-bound: 1.0.3 get-proto: 1.0.1 has-tostringtag: 1.0.2 safe-regex-test: 1.1.0 - dev: true - /is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 - dev: true - /is-negative-zero@2.0.2: - resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} - engines: {node: '>= 0.4'} - dev: true + is-negative-zero@2.0.2: {} - /is-number-object@1.0.7: - resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} - engines: {node: '>= 0.4'} + is-number-object@1.0.7: dependencies: has-tostringtag: 1.0.0 - dev: true - /is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - dev: true + is-number@7.0.0: {} - /is-plain-obj@1.1.0: - resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} - engines: {node: '>=0.10.0'} - dev: true + is-plain-obj@1.1.0: {} - /is-potential-custom-element-name@1.0.1: - resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} - dev: true + is-potential-custom-element-name@1.0.1: {} - /is-regex@1.1.4: - resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} - engines: {node: '>= 0.4'} + is-regex@1.1.4: dependencies: call-bind: 1.0.2 has-tostringtag: 1.0.0 - dev: true - /is-regex@1.2.1: - resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} - engines: {node: '>= 0.4'} + is-regex@1.2.1: dependencies: call-bound: 1.0.3 gopd: 1.2.0 has-tostringtag: 1.0.2 hasown: 2.0.2 - dev: true - /is-shared-array-buffer@1.0.2: - resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} + is-shared-array-buffer@1.0.2: dependencies: call-bind: 1.0.2 - dev: true - /is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - dev: true + is-stream@2.0.1: {} - /is-stream@3.0.0: - resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dev: true + is-stream@3.0.0: {} - /is-string@1.0.7: - resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} - engines: {node: '>= 0.4'} + is-string@1.0.7: dependencies: has-tostringtag: 1.0.0 - dev: true - /is-subdir@1.2.0: - resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} - engines: {node: '>=4'} + is-subdir@1.2.0: dependencies: better-path-resolve: 1.0.0 - dev: true - /is-symbol@1.0.4: - resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} - engines: {node: '>= 0.4'} + is-symbol@1.0.4: dependencies: has-symbols: 1.0.3 - dev: true - /is-typed-array@1.1.15: - resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} - engines: {node: '>= 0.4'} + is-typed-array@1.1.15: dependencies: which-typed-array: 1.1.18 - dev: true - /is-weakref@1.0.2: - resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + is-weakref@1.0.2: dependencies: call-bind: 1.0.2 - dev: true - /is-windows@1.0.2: - resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} - engines: {node: '>=0.10.0'} - dev: true + is-windows@1.0.2: {} - /is-wsl@2.2.0: - resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} - engines: {node: '>=8'} + is-wsl@2.2.0: dependencies: is-docker: 2.2.1 - dev: true - /isarray@1.0.0: - resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - dev: true + isarray@1.0.0: {} - /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true + isexe@2.0.0: {} - /istanbul-lib-coverage@3.2.0: - resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} - engines: {node: '>=8'} - dev: true + istanbul-lib-coverage@3.2.0: {} - /istanbul-lib-report@3.0.0: - resolution: {integrity: sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==} - engines: {node: '>=8'} + istanbul-lib-report@3.0.0: dependencies: istanbul-lib-coverage: 3.2.0 make-dir: 3.1.0 supports-color: 7.2.0 - dev: true - /istanbul-reports@3.1.5: - resolution: {integrity: sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==} - engines: {node: '>=8'} + istanbul-reports@3.1.5: dependencies: html-escaper: 2.0.2 istanbul-lib-report: 3.0.0 - dev: true - /jmespath@0.16.0: - resolution: {integrity: sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==} - engines: {node: '>= 0.6.0'} - dev: true + jmespath@0.16.0: {} - /jose@4.14.4: - resolution: {integrity: sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==} - dev: false + jose@4.14.4: {} - /joycon@3.1.1: - resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} - engines: {node: '>=10'} - dev: true + joycon@3.1.1: {} - /js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - dev: true + js-tokens@4.0.0: {} - /js-yaml@3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} - hasBin: true + js-yaml@3.14.1: dependencies: argparse: 1.0.10 esprima: 4.0.1 - dev: true - /js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true + js-yaml@4.1.0: dependencies: argparse: 2.0.1 - dev: true - /jsdom@20.0.3: - resolution: {integrity: sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==} - engines: {node: '>=14'} - peerDependencies: - canvas: ^2.5.0 - peerDependenciesMeta: - canvas: - optional: true + jsdom@20.0.3: dependencies: abab: 2.0.6 acorn: 8.8.1 @@ -4105,111 +5917,59 @@ packages: - bufferutil - supports-color - utf-8-validate - dev: true - /jsesc@2.5.2: - resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} - engines: {node: '>=4'} - hasBin: true - dev: true + jsesc@2.5.2: {} - /json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - dev: true + json-parse-even-better-errors@2.3.1: {} - /json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - dev: true + json-schema-traverse@0.4.1: {} - /json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - dev: true + json-stable-stringify-without-jsonify@1.0.1: {} - /json5@1.0.2: - resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} - hasBin: true + json5@1.0.2: dependencies: minimist: 1.2.6 - dev: true - /json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - dev: true + json5@2.2.3: {} - /jsonc-parser@3.2.0: - resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} - dev: true + jsonc-parser@3.2.0: {} - /jsonfile@4.0.0: - resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + jsonfile@4.0.0: optionalDependencies: graceful-fs: 4.2.10 - dev: true - /jsx-ast-utils@3.3.3: - resolution: {integrity: sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==} - engines: {node: '>=4.0'} + jsx-ast-utils@3.3.3: dependencies: array-includes: 3.1.5 object.assign: 4.1.4 - dev: true - /kind-of@6.0.3: - resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} - engines: {node: '>=0.10.0'} - dev: true + kind-of@6.0.3: {} - /kleur@4.1.5: - resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} - engines: {node: '>=6'} - dev: true + kleur@4.1.5: {} - /language-subtag-registry@0.3.22: - resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==} - dev: true + language-subtag-registry@0.3.22: {} - /language-tags@1.0.5: - resolution: {integrity: sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==} + language-tags@1.0.5: dependencies: language-subtag-registry: 0.3.22 - dev: true - /levn@0.3.0: - resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==} - engines: {node: '>= 0.8.0'} + levn@0.3.0: dependencies: prelude-ls: 1.1.2 type-check: 0.3.2 - dev: true - /levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} + levn@0.4.1: dependencies: prelude-ls: 1.2.1 type-check: 0.4.0 - dev: true - /lilconfig@2.0.5: - resolution: {integrity: sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==} - engines: {node: '>=10'} - dev: true + lilconfig@2.0.5: {} - /lilconfig@2.0.6: - resolution: {integrity: sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==} - engines: {node: '>=10'} - dev: true + lilconfig@2.0.6: {} - /lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - dev: true + lines-and-columns@1.2.4: {} - /lint-staged@13.0.3: - resolution: {integrity: sha512-9hmrwSCFroTSYLjflGI8Uk+GWAwMB4OlpU4bMJEAT5d/llQwtYKoim4bLOyLCuWFAhWEupE0vkIFqtw/WIsPug==} - engines: {node: ^14.13.1 || >=16.0.0} - hasBin: true + lint-staged@13.0.3(enquirer@2.3.6): dependencies: cli-truncate: 3.1.0 colorette: 2.0.19 @@ -4217,7 +5977,7 @@ packages: debug: 4.3.4 execa: 6.1.0 lilconfig: 2.0.5 - listr2: 4.0.5 + listr2: 4.0.5(enquirer@2.3.6) micromatch: 4.0.5 normalize-path: 3.0.0 object-inspect: 1.12.2 @@ -4227,16 +5987,8 @@ packages: transitivePeerDependencies: - enquirer - supports-color - dev: true - /listr2@4.0.5: - resolution: {integrity: sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA==} - engines: {node: '>=12'} - peerDependencies: - enquirer: '>= 2.3.0 < 3' - peerDependenciesMeta: - enquirer: - optional: true + listr2@4.0.5(enquirer@2.3.6): dependencies: cli-truncate: 2.1.0 colorette: 2.0.19 @@ -4246,145 +5998,85 @@ packages: rxjs: 7.5.6 through: 2.3.8 wrap-ansi: 7.0.0 - dev: true + optionalDependencies: + enquirer: 2.3.6 - /load-tsconfig@0.2.3: - resolution: {integrity: sha512-iyT2MXws+dc2Wi6o3grCFtGXpeMvHmJqS27sMPGtV2eUu4PeFnG+33I8BlFK1t1NWMjOpcx9bridn5yxLDX2gQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dev: true + load-tsconfig@0.2.3: {} - /load-yaml-file@0.2.0: - resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==} - engines: {node: '>=6'} + load-yaml-file@0.2.0: dependencies: graceful-fs: 4.2.10 js-yaml: 3.14.1 pify: 4.0.1 strip-bom: 3.0.0 - dev: true - /local-pkg@0.4.2: - resolution: {integrity: sha512-mlERgSPrbxU3BP4qBqAvvwlgW4MTg78iwJdGGnv7kibKjWcJksrG3t6LB5lXI93wXRDvG4NpUgJFmTG4T6rdrg==} - engines: {node: '>=14'} - dev: true + local-pkg@0.4.2: {} - /locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} + locate-path@5.0.0: dependencies: p-locate: 4.1.0 - dev: true - /locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} + locate-path@6.0.0: dependencies: p-locate: 5.0.0 - dev: true - /lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - dev: true + lodash.merge@4.6.2: {} - /lodash.sortby@4.7.0: - resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} - dev: true + lodash.sortby@4.7.0: {} - /lodash.startcase@4.4.0: - resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} - dev: true + lodash.startcase@4.4.0: {} - /log-update@4.0.0: - resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==} - engines: {node: '>=10'} + log-update@4.0.0: dependencies: ansi-escapes: 4.3.2 cli-cursor: 3.1.0 slice-ansi: 4.0.0 wrap-ansi: 6.2.0 - dev: true - /loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 - dev: true - /loupe@2.3.4: - resolution: {integrity: sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==} + loupe@2.3.4: dependencies: get-func-name: 2.0.0 - dev: true - /loupe@2.3.6: - resolution: {integrity: sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==} + loupe@2.3.6: dependencies: get-func-name: 2.0.0 - dev: true - /lru-cache@4.1.5: - resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} + lru-cache@4.1.5: dependencies: pseudomap: 1.0.2 yallist: 2.1.2 - dev: true - /lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 - dev: true - /lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} + lru-cache@6.0.0: dependencies: yallist: 4.0.0 - dev: true - /lz-string@1.4.4: - resolution: {integrity: sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==} - hasBin: true - dev: true + lz-string@1.4.4: {} - /magic-string@0.27.0: - resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} - engines: {node: '>=12'} + magic-string@0.27.0: dependencies: '@jridgewell/sourcemap-codec': 1.4.14 - dev: true - /make-dir@3.1.0: - resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} - engines: {node: '>=8'} + make-dir@3.1.0: dependencies: semver: 6.3.0 - dev: true - /map-obj@1.0.1: - resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} - engines: {node: '>=0.10.0'} - dev: true + map-obj@1.0.1: {} - /map-obj@4.3.0: - resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} - engines: {node: '>=8'} - dev: true + map-obj@4.3.0: {} - /math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - dev: true + math-intrinsics@1.1.0: {} - /media-typer@0.3.0: - resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} - engines: {node: '>= 0.6'} - dev: true + media-typer@0.3.0: {} - /meow@6.1.1: - resolution: {integrity: sha512-3YffViIt2QWgTy6Pale5QpopX/IvU3LPL03jOTqp6pGj3VjesdO/U8CuHMKpnQr4shCNCM5fd5XFFvIIl6JBHg==} - engines: {node: '>=8'} + meow@6.1.1: dependencies: '@types/minimist': 1.2.2 camelcase-keys: 6.2.2 @@ -4397,158 +6089,78 @@ packages: trim-newlines: 3.0.1 type-fest: 0.13.1 yargs-parser: 18.1.3 - dev: true - /merge-descriptors@1.0.1: - resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} - dev: true + merge-descriptors@1.0.1: {} - /merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - dev: true + merge-stream@2.0.0: {} - /merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - dev: true + merge2@1.4.1: {} - /methods@1.1.2: - resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} - engines: {node: '>= 0.6'} - dev: true + methods@1.1.2: {} - /micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} - engines: {node: '>=8.6'} + micromatch@4.0.5: dependencies: braces: 3.0.2 picomatch: 2.3.1 - dev: true - /mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - dev: true + mime-db@1.52.0: {} - /mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} + mime-types@2.1.35: dependencies: mime-db: 1.52.0 - dev: true - /mime@1.6.0: - resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} - engines: {node: '>=4'} - hasBin: true - dev: true + mime@1.6.0: {} - /mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} - dev: true + mimic-fn@2.1.0: {} - /mimic-fn@4.0.0: - resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} - engines: {node: '>=12'} - dev: true + mimic-fn@4.0.0: {} - /min-indent@1.0.1: - resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} - engines: {node: '>=4'} - dev: true + min-indent@1.0.1: {} - /minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 - dev: true - /minimatch@9.0.3: - resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} - engines: {node: '>=16 || 14 >=14.17'} + minimatch@9.0.3: dependencies: brace-expansion: 2.0.1 - dev: true - /minimist-options@4.1.0: - resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} - engines: {node: '>= 6'} + minimist-options@4.1.0: dependencies: arrify: 1.0.1 is-plain-obj: 1.1.0 kind-of: 6.0.3 - dev: true - /minimist@1.2.6: - resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==} - dev: true + minimist@1.2.6: {} - /mixme@0.5.5: - resolution: {integrity: sha512-/6IupbRx32s7jjEwHcycXikJwFD5UujbVNuJFkeKLYje+92OvtuPniF6JhnFm5JCTDUhS+kYK3W/4BWYQYXz7w==} - engines: {node: '>= 8.0.0'} - dev: true + mixme@0.5.5: {} - /mlly@1.1.0: - resolution: {integrity: sha512-cwzBrBfwGC1gYJyfcy8TcZU1f+dbH/T+TuOhtYP2wLv/Fb51/uV7HJQfBPtEupZ2ORLRU1EKFS/QfS3eo9+kBQ==} + mlly@1.1.0: dependencies: acorn: 8.8.1 pathe: 1.0.0 pkg-types: 1.0.1 ufo: 1.0.1 - dev: true - /ms@2.0.0: - resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - dev: true + ms@2.0.0: {} - /ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + ms@2.1.2: {} - /ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - dev: true + ms@2.1.3: {} - /mz@2.7.0: - resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + mz@2.7.0: dependencies: any-promise: 1.3.0 object-assign: 4.1.1 thenify-all: 1.6.0 - dev: true - /nanoid@3.3.4: - resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - dev: true + nanoid@3.3.4: {} - /natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - dev: true + natural-compare@1.4.0: {} - /negotiator@0.6.3: - resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} - engines: {node: '>= 0.6'} - dev: true + negotiator@0.6.3: {} - /next@12.3.0(@babel/core@7.20.12)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-GpzI6me9V1+XYtfK0Ae9WD0mKqHyzQlGq1xH1rzNIYMASo4Tkl4rTe9jSqtBpXFhOS33KohXs9ZY38Akkhdciw==} - engines: {node: '>=12.22.0'} - hasBin: true - peerDependencies: - fibers: '>= 3.1.0' - node-sass: ^6.0.0 || ^7.0.0 - react: ^17.0.2 || ^18.0.0-0 - react-dom: ^17.0.2 || ^18.0.0-0 - sass: ^1.3.0 - peerDependenciesMeta: - fibers: - optional: true - node-sass: - optional: true - sass: - optional: true + next@12.3.0(@babel/core@7.20.12)(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@next/env': 12.3.0 '@swc/helpers': 0.4.11 @@ -4575,11 +6187,8 @@ packages: transitivePeerDependencies: - '@babel/core' - babel-plugin-macros - dev: true - /node-mocks-http@1.11.0: - resolution: {integrity: sha512-jS/WzSOcKbOeGrcgKbenZeNhxUNnP36Yw11+hL4TTxQXErGfqYZ+MaYNNvhaTiGIJlzNSqgQkk9j8dSu1YWSuw==} - engines: {node: '>=0.6'} + node-mocks-http@1.11.0: dependencies: accepts: 1.3.8 content-disposition: 0.5.4 @@ -4591,134 +6200,83 @@ packages: parseurl: 1.3.3 range-parser: 1.2.1 type-is: 1.6.18 - dev: true - /node-releases@2.0.6: - resolution: {integrity: sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==} - dev: true + node-releases@2.0.6: {} - /normalize-package-data@2.5.0: - resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} + normalize-package-data@2.5.0: dependencies: hosted-git-info: 2.8.9 resolve: 1.22.1 semver: 5.7.2 validate-npm-package-license: 3.0.4 - dev: true - /normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - dev: true + normalize-path@3.0.0: {} - /npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} + npm-run-path@4.0.1: dependencies: path-key: 3.1.1 - dev: true - /npm-run-path@5.1.0: - resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + npm-run-path@5.1.0: dependencies: path-key: 4.0.0 - dev: true - /nwsapi@2.2.2: - resolution: {integrity: sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==} - dev: true + nwsapi@2.2.2: {} - /object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - dev: true + object-assign@4.1.1: {} - /object-inspect@1.12.2: - resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==} - dev: true + object-inspect@1.12.2: {} - /object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} - dev: true + object-keys@1.1.1: {} - /object.assign@4.1.4: - resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} - engines: {node: '>= 0.4'} + object.assign@4.1.4: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 has-symbols: 1.0.3 object-keys: 1.1.1 - dev: true - /object.entries@1.1.5: - resolution: {integrity: sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==} - engines: {node: '>= 0.4'} + object.entries@1.1.5: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 es-abstract: 1.20.2 - dev: true - /object.fromentries@2.0.5: - resolution: {integrity: sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==} - engines: {node: '>= 0.4'} + object.fromentries@2.0.5: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 es-abstract: 1.20.2 - dev: true - /object.hasown@1.1.1: - resolution: {integrity: sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==} + object.hasown@1.1.1: dependencies: define-properties: 1.1.4 es-abstract: 1.20.2 - dev: true - /object.values@1.1.5: - resolution: {integrity: sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==} - engines: {node: '>= 0.4'} + object.values@1.1.5: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 es-abstract: 1.20.2 - dev: true - /once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + once@1.4.0: dependencies: wrappy: 1.0.2 - dev: true - /onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} + onetime@5.1.2: dependencies: mimic-fn: 2.1.0 - dev: true - /onetime@6.0.0: - resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} - engines: {node: '>=12'} + onetime@6.0.0: dependencies: mimic-fn: 4.0.0 - dev: true - /open@8.4.0: - resolution: {integrity: sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==} - engines: {node: '>=12'} + open@8.4.0: dependencies: define-lazy-prop: 2.0.0 is-docker: 2.2.1 is-wsl: 2.2.0 - dev: true - /optionator@0.8.3: - resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} - engines: {node: '>= 0.8.0'} + optionator@0.8.3: dependencies: deep-is: 0.1.4 fast-levenshtein: 2.0.6 @@ -4726,11 +6284,8 @@ packages: prelude-ls: 1.1.2 type-check: 0.3.2 word-wrap: 1.2.5 - dev: true - /optionator@0.9.1: - resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} - engines: {node: '>= 0.8.0'} + optionator@0.9.1: dependencies: deep-is: 0.1.4 fast-levenshtein: 2.0.6 @@ -4738,598 +6293,328 @@ packages: prelude-ls: 1.2.1 type-check: 0.4.0 word-wrap: 1.2.5 - dev: true - /os-tmpdir@1.0.2: - resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} - engines: {node: '>=0.10.0'} - dev: true + os-tmpdir@1.0.2: {} - /outdent@0.5.0: - resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} - dev: true + outdent@0.5.0: {} - /p-filter@2.1.0: - resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} - engines: {node: '>=8'} + p-filter@2.1.0: dependencies: p-map: 2.1.0 - dev: true - /p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} + p-limit@2.3.0: dependencies: p-try: 2.2.0 - dev: true - /p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 - dev: true - /p-limit@4.0.0: - resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + p-limit@4.0.0: dependencies: yocto-queue: 1.0.0 - dev: true - /p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} + p-locate@4.1.0: dependencies: p-limit: 2.3.0 - dev: true - /p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} + p-locate@5.0.0: dependencies: p-limit: 3.1.0 - dev: true - /p-map@2.1.0: - resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} - engines: {node: '>=6'} - dev: true + p-map@2.1.0: {} - /p-map@4.0.0: - resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} - engines: {node: '>=10'} + p-map@4.0.0: dependencies: aggregate-error: 3.1.0 - dev: true - /p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} - dev: true + p-try@2.2.0: {} - /parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} + parent-module@1.0.1: dependencies: callsites: 3.1.0 - dev: true - /parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} + parse-json@5.2.0: dependencies: '@babel/code-frame': 7.18.6 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 - dev: true - /parse5@7.1.1: - resolution: {integrity: sha512-kwpuwzB+px5WUg9pyK0IcK/shltJN5/OVhQagxhCQNtT9Y9QRZqNY2e1cmbu/paRh5LMnz/oVTVLBpjFmMZhSg==} + parse5@7.1.1: dependencies: entities: 4.4.0 - dev: true - /parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - dev: true + parseurl@1.3.3: {} - /path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - dev: true + path-exists@4.0.0: {} - /path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - dev: true + path-is-absolute@1.0.1: {} - /path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - dev: true + path-key@3.1.1: {} - /path-key@4.0.0: - resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} - engines: {node: '>=12'} - dev: true + path-key@4.0.0: {} - /path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - dev: true + path-parse@1.0.7: {} - /path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - dev: true + path-type@4.0.0: {} - /pathe@0.2.0: - resolution: {integrity: sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==} - dev: true + pathe@0.2.0: {} - /pathe@1.0.0: - resolution: {integrity: sha512-nPdMG0Pd09HuSsr7QOKUXO2Jr9eqaDiZvDwdyIhNG5SHYujkQHYKDfGQkulBxvbDHz8oHLsTgKN86LSwYzSHAg==} - dev: true + pathe@1.0.0: {} - /pathe@1.1.0: - resolution: {integrity: sha512-ODbEPR0KKHqECXW1GoxdDb+AZvULmXjVPy4rt+pGo2+TnjJTIPJQSVS6N63n8T2Ip+syHhbn52OewKicV0373w==} - dev: true + pathe@1.1.0: {} - /pathval@1.1.1: - resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} - dev: true + pathval@1.1.1: {} - /picocolors@1.0.0: - resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - dev: true + picocolors@1.0.0: {} - /picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - dev: true + picomatch@2.3.1: {} - /pidtree@0.6.0: - resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} - engines: {node: '>=0.10'} - hasBin: true - dev: true + pidtree@0.6.0: {} - /pify@4.0.1: - resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} - engines: {node: '>=6'} - dev: true + pify@4.0.1: {} - /pirates@4.0.5: - resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==} - engines: {node: '>= 6'} - dev: true + pirates@4.0.5: {} - /pkg-dir@4.2.0: - resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} - engines: {node: '>=8'} + pkg-dir@4.2.0: dependencies: find-up: 4.1.0 - dev: true - /pkg-types@1.0.1: - resolution: {integrity: sha512-jHv9HB+Ho7dj6ItwppRDDl0iZRYBD0jsakHXtFgoLr+cHSF6xC+QL54sJmWxyGxOLYSHm0afhXhXcQDQqH9z8g==} + pkg-types@1.0.1: dependencies: jsonc-parser: 3.2.0 mlly: 1.1.0 pathe: 1.1.0 - dev: true - /possible-typed-array-names@1.0.0: - resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} - engines: {node: '>= 0.4'} - dev: true + possible-typed-array-names@1.0.0: {} - /postcss-load-config@3.1.4: - resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} - engines: {node: '>= 10'} - peerDependencies: - postcss: '>=8.0.9' - ts-node: '>=9.0.0' - peerDependenciesMeta: - postcss: - optional: true - ts-node: - optional: true + postcss-load-config@3.1.4(postcss@8.4.21): dependencies: lilconfig: 2.0.6 yaml: 1.10.2 - dev: true + optionalDependencies: + postcss: 8.4.21 - /postcss@8.4.14: - resolution: {integrity: sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==} - engines: {node: ^10 || ^12 || >=14} + postcss@8.4.14: dependencies: nanoid: 3.3.4 picocolors: 1.0.0 source-map-js: 1.0.2 - dev: true - /postcss@8.4.21: - resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==} - engines: {node: ^10 || ^12 || >=14} + postcss@8.4.21: dependencies: nanoid: 3.3.4 picocolors: 1.0.0 source-map-js: 1.0.2 - dev: true - /preferred-pm@3.0.3: - resolution: {integrity: sha512-+wZgbxNES/KlJs9q40F/1sfOd/j7f1O9JaHcW5Dsn3aUUOZg3L2bjpVUcKV2jvtElYfoTuQiNeMfQJ4kwUAhCQ==} - engines: {node: '>=10'} + preferred-pm@3.0.3: dependencies: find-up: 5.0.0 find-yarn-workspace-root2: 1.2.16 path-exists: 4.0.0 which-pm: 2.0.0 - dev: true - /prelude-ls@1.1.2: - resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} - engines: {node: '>= 0.8.0'} - dev: true + prelude-ls@1.1.2: {} - /prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - dev: true + prelude-ls@1.2.1: {} - /prettier@2.7.1: - resolution: {integrity: sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==} - engines: {node: '>=10.13.0'} - hasBin: true - dev: true + prettier@2.7.1: {} - /pretty-format@27.5.1: - resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + pretty-format@27.5.1: dependencies: ansi-regex: 5.0.1 ansi-styles: 5.2.0 react-is: 17.0.2 - dev: true - /prop-types@15.8.1: - resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 react-is: 16.13.1 - dev: true - /pseudomap@1.0.2: - resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} - dev: true + pseudomap@1.0.2: {} - /psl@1.9.0: - resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} - dev: true + psl@1.9.0: {} - /punycode@1.3.2: - resolution: {integrity: sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==} - dev: true + punycode@1.3.2: {} - /punycode@2.1.1: - resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} - engines: {node: '>=6'} - dev: true + punycode@2.1.1: {} - /query-string@7.1.3: - resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==} - engines: {node: '>=6'} + query-string@7.1.3: dependencies: decode-uri-component: 0.2.2 filter-obj: 1.1.0 split-on-first: 1.1.0 strict-uri-encode: 2.0.0 - dev: true - /querystring@0.2.0: - resolution: {integrity: sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==} - engines: {node: '>=0.4.x'} - deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead. - dev: true + querystring@0.2.0: {} - /querystringify@2.2.0: - resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} - dev: true + querystringify@2.2.0: {} - /queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - dev: true + queue-microtask@1.2.3: {} - /quick-lru@4.0.1: - resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} - engines: {node: '>=8'} - dev: true + quick-lru@4.0.1: {} - /range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} - dev: true + range-parser@1.2.1: {} - /raw-body@2.5.2: - resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} - engines: {node: '>= 0.8'} + raw-body@2.5.2: dependencies: bytes: 3.1.2 http-errors: 2.0.0 iconv-lite: 0.4.24 unpipe: 1.0.0 - dev: false - /react-dom@18.2.0(react@18.2.0): - resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} - peerDependencies: - react: ^18.2.0 + react-dom@18.2.0(react@18.2.0): dependencies: loose-envify: 1.4.0 react: 18.2.0 scheduler: 0.23.0 - dev: true - /react-is@16.13.1: - resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - dev: true + react-is@16.13.1: {} - /react-is@17.0.2: - resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} - dev: true + react-is@17.0.2: {} - /react-refresh@0.14.0: - resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} - engines: {node: '>=0.10.0'} - dev: true + react-refresh@0.14.0: {} - /react@18.2.0: - resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} - engines: {node: '>=0.10.0'} + react@18.2.0: dependencies: loose-envify: 1.4.0 - dev: true - /read-pkg-up@7.0.1: - resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} - engines: {node: '>=8'} + read-pkg-up@7.0.1: dependencies: find-up: 4.1.0 read-pkg: 5.2.0 type-fest: 0.8.1 - dev: true - /read-pkg@5.2.0: - resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} - engines: {node: '>=8'} + read-pkg@5.2.0: dependencies: '@types/normalize-package-data': 2.4.1 normalize-package-data: 2.5.0 parse-json: 5.2.0 type-fest: 0.6.0 - dev: true - /read-yaml-file@1.1.0: - resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} - engines: {node: '>=6'} + read-yaml-file@1.1.0: dependencies: graceful-fs: 4.2.10 js-yaml: 3.14.1 pify: 4.0.1 strip-bom: 3.0.0 - dev: true - /readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} + readdirp@3.6.0: dependencies: picomatch: 2.3.1 - dev: true - /redent@3.0.0: - resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} - engines: {node: '>=8'} + redent@3.0.0: dependencies: indent-string: 4.0.0 strip-indent: 3.0.0 - dev: true - /regenerator-runtime@0.13.11: - resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} - dev: true + regenerator-runtime@0.13.11: {} - /regenerator-runtime@0.13.9: - resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==} - dev: true + regenerator-runtime@0.13.9: {} - /regexp.prototype.flags@1.4.3: - resolution: {integrity: sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==} - engines: {node: '>= 0.4'} + regexp.prototype.flags@1.4.3: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 functions-have-names: 1.2.3 - dev: true - /regexpp@3.2.0: - resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} - engines: {node: '>=8'} - dev: true + regexpp@3.2.0: {} - /require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - dev: true + require-directory@2.1.1: {} - /require-main-filename@2.0.0: - resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} - dev: true + require-main-filename@2.0.0: {} - /requires-port@1.0.0: - resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} - dev: true + requires-port@1.0.0: {} - /resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - dev: true + resolve-from@4.0.0: {} - /resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} - dev: true + resolve-from@5.0.0: {} - /resolve@1.22.1: - resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} - hasBin: true + resolve@1.22.1: dependencies: is-core-module: 2.10.0 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - dev: true - /resolve@2.0.0-next.4: - resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==} - hasBin: true + resolve@2.0.0-next.4: dependencies: is-core-module: 2.10.0 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - dev: true - /restore-cursor@3.1.0: - resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} - engines: {node: '>=8'} + restore-cursor@3.1.0: dependencies: onetime: 5.1.2 signal-exit: 3.0.7 - dev: true - /retes@0.33.0: - resolution: {integrity: sha512-I6V1G2JkJ2JFIFSVuultNXepf7BW8SCaSUOq5IETM2fDjFim5Dg5F1zU/QbplNW0mqkk8QCw+I722v3nPkpRlA==} + retes@0.33.0: dependencies: busboy: 1.6.0 zod: 3.19.1 - dev: false - /reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - dev: true + reusify@1.0.4: {} - /rfdc@1.3.0: - resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==} - dev: true + rfdc@1.3.0: {} - /rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - hasBin: true + rimraf@3.0.2: dependencies: glob: 7.2.3 - dev: true - /rollup@2.79.0: - resolution: {integrity: sha512-x4KsrCgwQ7ZJPcFA/SUu6QVcYlO7uRLfLAy0DSA4NS2eG8japdbpM50ToH7z4iObodRYOJ0soneF0iaQRJ6zhA==} - engines: {node: '>=10.0.0'} - hasBin: true + rollup@2.79.0: optionalDependencies: fsevents: 2.3.3 - dev: true - /rollup@3.10.1: - resolution: {integrity: sha512-3Er+yel3bZbZX1g2kjVM+FW+RUWDxbG87fcqFM5/9HbPCTpbVp6JOLn7jlxnNlbu7s/N/uDA4EV/91E2gWnxzw==} - engines: {node: '>=14.18.0', npm: '>=8.0.0'} - hasBin: true + rollup@3.10.1: optionalDependencies: fsevents: 2.3.3 - dev: true - /run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 - dev: true - /rxjs@7.5.6: - resolution: {integrity: sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw==} + rxjs@7.5.6: dependencies: tslib: 2.4.0 - dev: true - /safe-buffer@5.1.2: - resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - dev: true + safe-buffer@5.1.2: {} - /safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - dev: true + safe-buffer@5.2.1: {} - /safe-regex-test@1.1.0: - resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} - engines: {node: '>= 0.4'} + safe-regex-test@1.1.0: dependencies: call-bound: 1.0.3 es-errors: 1.3.0 is-regex: 1.2.1 - dev: true - /safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + safer-buffer@2.1.2: {} - /sax@1.2.1: - resolution: {integrity: sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==} - dev: true + sax@1.2.1: {} - /saxes@6.0.0: - resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} - engines: {node: '>=v12.22.7'} + saxes@6.0.0: dependencies: xmlchars: 2.2.0 - dev: true - /scheduler@0.23.0: - resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} + scheduler@0.23.0: dependencies: loose-envify: 1.4.0 - dev: true - /semver@5.7.2: - resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} - hasBin: true - dev: true + semver@5.7.2: {} - /semver@6.3.0: - resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} - hasBin: true - dev: true + semver@6.3.0: {} - /semver@7.5.4: - resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} - engines: {node: '>=10'} - hasBin: true + semver@7.5.4: dependencies: lru-cache: 6.0.0 - dev: true - /semver@7.6.0: - resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} - engines: {node: '>=10'} - hasBin: true + semver@7.6.0: dependencies: lru-cache: 6.0.0 - dev: true - /set-blocking@2.0.0: - resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - dev: true + set-blocking@2.0.0: {} - /set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 es-errors: 1.3.0 @@ -5337,92 +6622,53 @@ packages: get-intrinsic: 1.2.7 gopd: 1.2.0 has-property-descriptors: 1.0.2 - dev: true - /setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - dev: false + setprototypeof@1.2.0: {} - /shebang-command@1.2.0: - resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} - engines: {node: '>=0.10.0'} + shebang-command@1.2.0: dependencies: shebang-regex: 1.0.0 - dev: true - /shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 - dev: true - /shebang-regex@1.0.0: - resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} - engines: {node: '>=0.10.0'} - dev: true + shebang-regex@1.0.0: {} - /shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - dev: true + shebang-regex@3.0.0: {} - /side-channel@1.0.4: - resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + side-channel@1.0.4: dependencies: call-bind: 1.0.2 get-intrinsic: 1.1.2 object-inspect: 1.12.2 - dev: true - /siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - dev: true + siginfo@2.0.0: {} - /signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - dev: true + signal-exit@3.0.7: {} - /slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - dev: true + slash@3.0.0: {} - /slash@4.0.0: - resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} - engines: {node: '>=12'} - dev: true + slash@4.0.0: {} - /slice-ansi@3.0.0: - resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} - engines: {node: '>=8'} + slice-ansi@3.0.0: dependencies: ansi-styles: 4.3.0 astral-regex: 2.0.0 is-fullwidth-code-point: 3.0.0 - dev: true - /slice-ansi@4.0.0: - resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} - engines: {node: '>=10'} + slice-ansi@4.0.0: dependencies: ansi-styles: 4.3.0 astral-regex: 2.0.0 is-fullwidth-code-point: 3.0.0 - dev: true - /slice-ansi@5.0.0: - resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} - engines: {node: '>=12'} + slice-ansi@5.0.0: dependencies: ansi-styles: 6.1.0 is-fullwidth-code-point: 4.0.0 - dev: true - /smartwrap@2.0.2: - resolution: {integrity: sha512-vCsKNQxb7PnCNd2wY1WClWifAc2lwqsG8OaswpJkVJsvMGcnEntdTCDajZCkk93Ay1U3t/9puJmb525Rg5MZBA==} - engines: {node: '>=6'} - hasBin: true + smartwrap@2.0.2: dependencies: array.prototype.flat: 1.3.0 breakword: 1.0.5 @@ -5430,125 +6676,72 @@ packages: strip-ansi: 6.0.1 wcwidth: 1.0.1 yargs: 15.4.1 - dev: true - /source-map-js@1.0.2: - resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} - engines: {node: '>=0.10.0'} - dev: true + source-map-js@1.0.2: {} - /source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + source-map-support@0.5.21: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 - dev: true - /source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - requiresBuild: true - dev: true + source-map@0.6.1: {} - /source-map@0.8.0-beta.0: - resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} - engines: {node: '>= 8'} + source-map@0.8.0-beta.0: dependencies: whatwg-url: 7.1.0 - dev: true - /spawndamnit@2.0.0: - resolution: {integrity: sha512-j4JKEcncSjFlqIwU5L/rp2N5SIPsdxaRsIv678+TZxZ0SRDJTm8JrxJMjE/XuiEZNEir3S8l0Fa3Ke339WI4qA==} + spawndamnit@2.0.0: dependencies: cross-spawn: 5.1.0 signal-exit: 3.0.7 - dev: true - /spdx-correct@3.1.1: - resolution: {integrity: sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==} + spdx-correct@3.1.1: dependencies: spdx-expression-parse: 3.0.1 spdx-license-ids: 3.0.12 - dev: true - /spdx-exceptions@2.3.0: - resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} - dev: true + spdx-exceptions@2.3.0: {} - /spdx-expression-parse@3.0.1: - resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + spdx-expression-parse@3.0.1: dependencies: spdx-exceptions: 2.3.0 spdx-license-ids: 3.0.12 - dev: true - /spdx-license-ids@3.0.12: - resolution: {integrity: sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==} - dev: true + spdx-license-ids@3.0.12: {} - /split-on-first@1.1.0: - resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==} - engines: {node: '>=6'} - dev: true + split-on-first@1.1.0: {} - /sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - dev: true + sprintf-js@1.0.3: {} - /stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - dev: true + stackback@0.0.2: {} - /statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} - engines: {node: '>= 0.8'} - dev: false + statuses@2.0.1: {} - /std-env@3.3.1: - resolution: {integrity: sha512-3H20QlwQsSm2OvAxWIYhs+j01MzzqwMwGiiO1NQaJYZgJZFPuAbf95/DiKRBSTYIJ2FeGUc+B/6mPGcWP9dO3Q==} - dev: true + std-env@3.3.1: {} - /stream-transform@2.1.3: - resolution: {integrity: sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==} + stream-transform@2.1.3: dependencies: mixme: 0.5.5 - dev: true - /streamsearch@1.1.0: - resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} - engines: {node: '>=10.0.0'} - dev: false + streamsearch@1.1.0: {} - /strict-uri-encode@2.0.0: - resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} - engines: {node: '>=4'} - dev: true + strict-uri-encode@2.0.0: {} - /string-argv@0.3.1: - resolution: {integrity: sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==} - engines: {node: '>=0.6.19'} - dev: true + string-argv@0.3.1: {} - /string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - dev: true - /string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} + string-width@5.1.2: dependencies: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 strip-ansi: 7.0.1 - dev: true - /string.prototype.matchall@4.0.7: - resolution: {integrity: sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==} + string.prototype.matchall@4.0.7: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 @@ -5558,92 +6751,50 @@ packages: internal-slot: 1.0.3 regexp.prototype.flags: 1.4.3 side-channel: 1.0.4 - dev: true - /string.prototype.trimend@1.0.5: - resolution: {integrity: sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==} + string.prototype.trimend@1.0.5: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 es-abstract: 1.20.2 - dev: true - /string.prototype.trimstart@1.0.5: - resolution: {integrity: sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==} + string.prototype.trimstart@1.0.5: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 es-abstract: 1.20.2 - dev: true - /strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 - dev: true - /strip-ansi@7.0.1: - resolution: {integrity: sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==} - engines: {node: '>=12'} + strip-ansi@7.0.1: dependencies: ansi-regex: 6.0.1 - dev: true - /strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} - dev: true + strip-bom@3.0.0: {} - /strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} - dev: true + strip-final-newline@2.0.0: {} - /strip-final-newline@3.0.0: - resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} - engines: {node: '>=12'} - dev: true + strip-final-newline@3.0.0: {} - /strip-indent@3.0.0: - resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} - engines: {node: '>=8'} + strip-indent@3.0.0: dependencies: min-indent: 1.0.1 - dev: true - /strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - dev: true + strip-json-comments@3.1.1: {} - /strip-literal@1.0.0: - resolution: {integrity: sha512-5o4LsH1lzBzO9UFH63AJ2ad2/S2AVx6NtjOcaz+VTT2h1RiRvbipW72z8M/lxEhcPHDBQwpDrnTF7sXy/7OwCQ==} + strip-literal@1.0.0: dependencies: acorn: 8.8.1 - dev: true - /styled-jsx@5.0.6(@babel/core@7.20.12)(react@18.2.0): - resolution: {integrity: sha512-xOeROtkK5MGMDimBQ3J6iPId8q0t/BDoG5XN6oKkZClVz9ISF/hihN8OCn2LggMU6N32aXnrXBdn3auSqNS9fA==} - engines: {node: '>= 12.0.0'} - peerDependencies: - '@babel/core': '*' - babel-plugin-macros: '*' - react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' - peerDependenciesMeta: - '@babel/core': - optional: true - babel-plugin-macros: - optional: true + styled-jsx@5.0.6(@babel/core@7.20.12)(react@18.2.0): dependencies: - '@babel/core': 7.20.12 react: 18.2.0 - dev: true + optionalDependencies: + '@babel/core': 7.20.12 - /sucrase@3.25.0: - resolution: {integrity: sha512-WxTtwEYXSmZArPGStGBicyRsg5TBEFhT5b7N+tF+zauImP0Acy+CoUK0/byJ8JNPK/5lbpWIVuFagI4+0l85QQ==} - engines: {node: '>=8'} - hasBin: true + sucrase@3.25.0: dependencies: commander: 4.1.1 glob: 7.1.6 @@ -5651,210 +6802,110 @@ packages: mz: 2.7.0 pirates: 4.0.5 ts-interface-checker: 0.1.13 - dev: true - /supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} + supports-color@5.5.0: dependencies: has-flag: 3.0.0 - dev: true - /supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} + supports-color@7.2.0: dependencies: has-flag: 4.0.0 - dev: true - /supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - dev: true + supports-preserve-symlinks-flag@1.0.0: {} - /symbol-tree@3.2.4: - resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - dev: true + symbol-tree@3.2.4: {} - /synckit@0.8.4: - resolution: {integrity: sha512-Dn2ZkzMdSX827QbowGbU/4yjWuvNaCoScLLoMo/yKbu+P4GBR6cRGKZH27k6a9bRzdqcyd1DE96pQtQ6uNkmyw==} - engines: {node: ^14.18.0 || >=16.0.0} + synckit@0.8.4: dependencies: '@pkgr/utils': 2.3.1 tslib: 2.4.0 - dev: true - /tapable@2.2.1: - resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} - engines: {node: '>=6'} - dev: true + tapable@2.2.1: {} - /term-size@2.2.1: - resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} - engines: {node: '>=8'} - dev: true + term-size@2.2.1: {} - /test-exclude@6.0.0: - resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} - engines: {node: '>=8'} + test-exclude@6.0.0: dependencies: '@istanbuljs/schema': 0.1.3 glob: 7.2.3 minimatch: 3.1.2 - dev: true - /text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - dev: true + text-table@0.2.0: {} - /thenify-all@1.6.0: - resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} - engines: {node: '>=0.8'} + thenify-all@1.6.0: dependencies: thenify: 3.3.1 - dev: true - /thenify@3.3.1: - resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + thenify@3.3.1: dependencies: any-promise: 1.3.0 - dev: true - /through@2.3.8: - resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - dev: true + through@2.3.8: {} - /tiny-glob@0.2.9: - resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} + tiny-glob@0.2.9: dependencies: globalyzer: 0.1.0 globrex: 0.1.2 - dev: true - /tinybench@2.3.1: - resolution: {integrity: sha512-hGYWYBMPr7p4g5IarQE7XhlyWveh1EKhy4wUBS1LrHXCKYgvz+4/jCqgmJqZxxldesn05vccrtME2RLLZNW7iA==} - dev: true + tinybench@2.3.1: {} - /tinypool@0.3.0: - resolution: {integrity: sha512-NX5KeqHOBZU6Bc0xj9Vr5Szbb1j8tUHIeD18s41aDJaPeC5QTdEhK0SpdpUrZlj2nv5cctNcSjaKNanXlfcVEQ==} - engines: {node: '>=14.0.0'} - dev: true + tinypool@0.3.0: {} - /tinyspy@1.0.2: - resolution: {integrity: sha512-bSGlgwLBYf7PnUsQ6WOc6SJ3pGOcd+d8AA6EUnLDDM0kWEstC1JIlSZA3UNliDXhd9ABoS7hiRBDCu+XP/sf1Q==} - engines: {node: '>=14.0.0'} - dev: true + tinyspy@1.0.2: {} - /tmp@0.0.33: - resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} - engines: {node: '>=0.6.0'} + tmp@0.0.33: dependencies: os-tmpdir: 1.0.2 - dev: true - /to-fast-properties@2.0.0: - resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} - engines: {node: '>=4'} - dev: true + to-fast-properties@2.0.0: {} - /to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - dev: true - /toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - dev: false + toidentifier@1.0.1: {} - /tough-cookie@4.1.3: - resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==} - engines: {node: '>=6'} + tough-cookie@4.1.3: dependencies: psl: 1.9.0 punycode: 2.1.1 universalify: 0.2.0 url-parse: 1.5.10 - dev: true - /tr46@1.0.1: - resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} + tr46@1.0.1: dependencies: punycode: 2.1.1 - dev: true - /tr46@3.0.0: - resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==} - engines: {node: '>=12'} + tr46@3.0.0: dependencies: punycode: 2.1.1 - dev: true - /tree-kill@1.2.2: - resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} - hasBin: true - dev: true + tree-kill@1.2.2: {} - /trim-newlines@3.0.1: - resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} - engines: {node: '>=8'} - dev: true + trim-newlines@3.0.1: {} - /ts-api-utils@1.2.1(typescript@5.4.2): - resolution: {integrity: sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==} - engines: {node: '>=16'} - peerDependencies: - typescript: '>=4.2.0' + ts-api-utils@1.2.1(typescript@5.4.2): dependencies: typescript: 5.4.2 - dev: true - /ts-interface-checker@0.1.13: - resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - dev: true + ts-interface-checker@0.1.13: {} - /tsconfig-paths@3.14.1: - resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==} + tsconfig-paths@3.14.1: dependencies: '@types/json5': 0.0.29 json5: 1.0.2 minimist: 1.2.6 strip-bom: 3.0.0 - dev: true - /tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - dev: true + tslib@1.14.1: {} - /tslib@2.4.0: - resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} - dev: true + tslib@2.4.0: {} - /tsm@2.2.2: - resolution: {integrity: sha512-bXkt675NbbqfwRHSSn8kSNEEHvoIUFDM9G6tUENkjEKpAEbrEzieO3PxUiRJylMw8fEGpcf5lSjadzzz12pc2A==} - engines: {node: '>=12'} - hasBin: true + tsm@2.2.2: dependencies: esbuild: 0.14.54 - dev: true - /tsup@6.2.3(typescript@5.4.2): - resolution: {integrity: sha512-J5Pu2Dx0E1wlpIEsVFv9ryzP1pZ1OYsJ2cBHZ7GrKteytNdzaSz5hmLX7/nAxtypq+jVkVvA79d7S83ETgHQ5w==} - engines: {node: '>=14'} - hasBin: true - peerDependencies: - '@swc/core': ^1 - postcss: ^8.4.12 - typescript: ^4.1.0 - peerDependenciesMeta: - '@swc/core': - optional: true - postcss: - optional: true - typescript: - optional: true + tsup@6.2.3(postcss@8.4.21)(typescript@5.4.2): dependencies: bundle-require: 3.1.0(esbuild@0.15.7) cac: 6.7.14 @@ -5864,32 +6915,25 @@ packages: execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 - postcss-load-config: 3.1.4 + postcss-load-config: 3.1.4(postcss@8.4.21) resolve-from: 5.0.0 rollup: 2.79.0 source-map: 0.8.0-beta.0 sucrase: 3.25.0 tree-kill: 1.2.2 + optionalDependencies: + postcss: 8.4.21 typescript: 5.4.2 transitivePeerDependencies: - supports-color - ts-node - dev: true - /tsutils@3.21.0(typescript@5.4.2): - resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} - engines: {node: '>= 6'} - peerDependencies: - typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + tsutils@3.21.0(typescript@5.4.2): dependencies: tslib: 1.14.1 typescript: 5.4.2 - dev: true - /tty-table@4.1.6: - resolution: {integrity: sha512-kRj5CBzOrakV4VRRY5kUWbNYvo/FpOsz65DzI5op9P+cHov3+IqPbo1JE1ZnQGkHdZgNFDsrEjrfqqy/Ply9fw==} - engines: {node: '>=8.0.0'} - hasBin: true + tty-table@4.1.6: dependencies: chalk: 4.1.2 csv: 5.5.3 @@ -5898,180 +6942,102 @@ packages: strip-ansi: 6.0.1 wcwidth: 1.0.1 yargs: 17.6.2 - dev: true - /type-check@0.3.2: - resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} - engines: {node: '>= 0.8.0'} + type-check@0.3.2: dependencies: prelude-ls: 1.1.2 - dev: true - /type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 - dev: true - /type-detect@4.0.8: - resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} - engines: {node: '>=4'} - dev: true + type-detect@4.0.8: {} - /type-fest@0.13.1: - resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} - engines: {node: '>=10'} - dev: true + type-fest@0.13.1: {} - /type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - dev: true + type-fest@0.20.2: {} - /type-fest@0.21.3: - resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} - engines: {node: '>=10'} - dev: true + type-fest@0.21.3: {} - /type-fest@0.6.0: - resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} - engines: {node: '>=8'} - dev: true + type-fest@0.6.0: {} - /type-fest@0.8.1: - resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} - engines: {node: '>=8'} - dev: true + type-fest@0.8.1: {} - /type-is@1.6.18: - resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} - engines: {node: '>= 0.6'} + type-is@1.6.18: dependencies: media-typer: 0.3.0 mime-types: 2.1.35 - dev: true - /typescript@5.4.2: - resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==} - engines: {node: '>=14.17'} - hasBin: true - dev: true + typescript@5.4.2: {} - /ufo@1.0.1: - resolution: {integrity: sha512-boAm74ubXHY7KJQZLlXrtMz52qFvpsbOxDcZOnw/Wf+LS4Mmyu7JxmzD4tDLtUQtmZECypJ0FrCz4QIe6dvKRA==} - dev: true + ufo@1.0.1: {} - /unbox-primitive@1.0.2: - resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + unbox-primitive@1.0.2: dependencies: call-bind: 1.0.2 has-bigints: 1.0.2 has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 - dev: true - /universalify@0.1.2: - resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} - engines: {node: '>= 4.0.0'} - dev: true + universalify@0.1.2: {} - /universalify@0.2.0: - resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} - engines: {node: '>= 4.0.0'} - dev: true + universalify@0.2.0: {} - /unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - dev: false + unpipe@1.0.0: {} - /update-browserslist-db@1.0.7(browserslist@4.21.3): - resolution: {integrity: sha512-iN/XYesmZ2RmmWAiI4Z5rq0YqSiv0brj9Ce9CfhNE4xIW2h+MFxcgkxIzZ+ShkFPUkjU3gQ+3oypadD3RAMtrg==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' + update-browserslist-db@1.0.7(browserslist@4.21.3): dependencies: browserslist: 4.21.3 escalade: 3.1.1 picocolors: 1.0.0 - dev: true - /uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + uri-js@4.4.1: dependencies: punycode: 2.1.1 - dev: true - /url-parse@1.5.10: - resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + url-parse@1.5.10: dependencies: querystringify: 2.2.0 requires-port: 1.0.0 - dev: true - /url@0.10.3: - resolution: {integrity: sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==} + url@0.10.3: dependencies: punycode: 1.3.2 querystring: 0.2.0 - dev: true - /use-sync-external-store@1.2.0(react@18.2.0): - resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 + use-sync-external-store@1.2.0(react@18.2.0): dependencies: react: 18.2.0 - dev: true - /util@0.12.5: - resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} + util@0.12.5: dependencies: inherits: 2.0.4 is-arguments: 1.2.0 is-generator-function: 1.1.0 is-typed-array: 1.1.15 which-typed-array: 1.1.18 - dev: true - /uuid@8.0.0: - resolution: {integrity: sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==} - hasBin: true - dev: true + uuid@8.0.0: {} - /uuid@9.0.0: - resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==} - hasBin: true - dev: false + uuid@9.0.0: {} - /v8-to-istanbul@9.0.1: - resolution: {integrity: sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==} - engines: {node: '>=10.12.0'} + v8-to-istanbul@9.0.1: dependencies: '@jridgewell/trace-mapping': 0.3.15 '@types/istanbul-lib-coverage': 2.0.4 convert-source-map: 1.8.0 - dev: true - /validate-npm-package-license@3.0.4: - resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + validate-npm-package-license@3.0.4: dependencies: spdx-correct: 3.1.1 spdx-expression-parse: 3.0.1 - dev: true - /vi-fetch@0.8.0: - resolution: {integrity: sha512-uvEgEBTacSnlxRcoA56Drwkc2LbTvRNOdSx5MVayBfEsHAgQJAu+LwePlUOkidFsqQMcQxcb+LlC9qZ9v1yXiw==} + vi-fetch@0.8.0: dependencies: query-string: 7.1.3 tinyspy: 1.0.2 - dev: true - /vite-node@0.27.2(@types/node@18.7.15): - resolution: {integrity: sha512-IDwuVhslF10qCnWOGJui7/2KksAOBHi+UbVo6Pqt4f5lgn+kS2sVvYDsETRG5PSuslisGB5CFGvb9I6FQgymBQ==} - engines: {node: '>=v14.16.0'} - hasBin: true + vite-node@0.27.2(@types/node@18.7.15): dependencies: cac: 6.7.14 debug: 4.3.4 @@ -6089,12 +7055,8 @@ packages: - sugarss - supports-color - terser - dev: true - /vite-node@0.28.1(@types/node@18.7.15): - resolution: {integrity: sha512-Mmab+cIeElkVn4noScCRjy8nnQdh5LDIR4QCH/pVWtY15zv5Z1J7u6/471B9JZ2r8CEIs42vTbngaamOVkhPLA==} - engines: {node: '>=v14.16.0'} - hasBin: true + vite-node@0.28.1(@types/node@18.7.15): dependencies: cac: 6.7.14 debug: 4.3.4 @@ -6112,63 +7074,18 @@ packages: - sugarss - supports-color - terser - dev: true - /vite@4.0.5(@types/node@18.7.15): - resolution: {integrity: sha512-7m87RC+caiAxG+8j3jObveRLqaWA/neAdCat6JAZwMkSWqFHOvg8MYe5fAQxVBRAuKAQ1S6XDh3CBQuLNbY33w==} - engines: {node: ^14.18.0 || >=16.0.0} - hasBin: true - peerDependencies: - '@types/node': '>= 14' - less: '*' - sass: '*' - stylus: '*' - sugarss: '*' - terser: ^5.4.0 - peerDependenciesMeta: - '@types/node': - optional: true - less: - optional: true - sass: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true + vite@4.0.5(@types/node@18.7.15): dependencies: - '@types/node': 18.7.15 esbuild: 0.16.17 postcss: 8.4.21 resolve: 1.22.1 rollup: 3.10.1 optionalDependencies: + '@types/node': 18.7.15 fsevents: 2.3.3 - dev: true - /vitest@0.27.2(jsdom@20.0.3): - resolution: {integrity: sha512-y7tdsL2uaQy+KF18AlmNHZe29ukyFytlxrpSTwwmgLE2XHR/aPucJP9FLjWoqjgqFlXzRAjHlFJLU+HDyI/OsA==} - engines: {node: '>=v14.16.0'} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@vitest/browser': '*' - '@vitest/ui': '*' - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@vitest/browser': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true + vitest@0.27.2(jsdom@20.0.3): dependencies: '@types/chai': 4.3.4 '@types/chai-subset': 1.3.3 @@ -6178,7 +7095,6 @@ packages: cac: 6.7.14 chai: 4.3.7 debug: 4.3.4 - jsdom: 20.0.3 local-pkg: 0.4.2 picocolors: 1.0.0 source-map: 0.6.1 @@ -6189,6 +7105,8 @@ packages: vite: 4.0.5(@types/node@18.7.15) vite-node: 0.27.2(@types/node@18.7.15) why-is-node-running: 2.2.2 + optionalDependencies: + jsdom: 20.0.3 transitivePeerDependencies: - less - sass @@ -6196,29 +7114,8 @@ packages: - sugarss - supports-color - terser - dev: true - /vitest@0.28.1(jsdom@20.0.3): - resolution: {integrity: sha512-F6wAO3K5+UqJCCGt0YAl3Ila2f+fpBrJhl9n7qWEhREwfzQeXlMkkCqGqGtzBxCSa8kv5QHrkshX8AaPTXYACQ==} - engines: {node: '>=v14.16.0'} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@vitest/browser': '*' - '@vitest/ui': '*' - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@vitest/browser': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true + vitest@0.28.1(jsdom@20.0.3): dependencies: '@types/chai': 4.3.4 '@types/chai-subset': 1.3.3 @@ -6232,7 +7129,6 @@ packages: cac: 6.7.14 chai: 4.3.7 debug: 4.3.4 - jsdom: 20.0.3 local-pkg: 0.4.2 pathe: 1.1.0 picocolors: 1.0.0 @@ -6245,6 +7141,8 @@ packages: vite: 4.0.5(@types/node@18.7.15) vite-node: 0.28.1(@types/node@18.7.15) why-is-node-running: 2.2.2 + optionalDependencies: + jsdom: 20.0.3 transitivePeerDependencies: - less - sass @@ -6252,91 +7150,57 @@ packages: - sugarss - supports-color - terser - dev: true - /w3c-xmlserializer@4.0.0: - resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==} - engines: {node: '>=14'} + w3c-xmlserializer@4.0.0: dependencies: xml-name-validator: 4.0.0 - dev: true - /watchpack@2.4.2: - resolution: {integrity: sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==} - engines: {node: '>=10.13.0'} + watchpack@2.4.2: dependencies: glob-to-regexp: 0.4.1 graceful-fs: 4.2.10 - dev: true - /wcwidth@1.0.1: - resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + wcwidth@1.0.1: dependencies: defaults: 1.0.3 - dev: true - /webidl-conversions@4.0.2: - resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} - dev: true + webidl-conversions@4.0.2: {} - /webidl-conversions@7.0.0: - resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} - engines: {node: '>=12'} - dev: true + webidl-conversions@7.0.0: {} - /whatwg-encoding@2.0.0: - resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} - engines: {node: '>=12'} + whatwg-encoding@2.0.0: dependencies: iconv-lite: 0.6.3 - dev: true - /whatwg-mimetype@3.0.0: - resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} - engines: {node: '>=12'} - dev: true + whatwg-mimetype@3.0.0: {} - /whatwg-url@11.0.0: - resolution: {integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==} - engines: {node: '>=12'} + whatwg-url@11.0.0: dependencies: tr46: 3.0.0 webidl-conversions: 7.0.0 - dev: true - /whatwg-url@7.1.0: - resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} + whatwg-url@7.1.0: dependencies: lodash.sortby: 4.7.0 tr46: 1.0.1 webidl-conversions: 4.0.2 - dev: true - /which-boxed-primitive@1.0.2: - resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + which-boxed-primitive@1.0.2: dependencies: is-bigint: 1.0.4 is-boolean-object: 1.1.2 is-number-object: 1.0.7 is-string: 1.0.7 is-symbol: 1.0.4 - dev: true - /which-module@2.0.0: - resolution: {integrity: sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==} - dev: true + which-module@2.0.0: {} - /which-pm@2.0.0: - resolution: {integrity: sha512-Lhs9Pmyph0p5n5Z3mVnN0yWcbQYUAD7rbQUiMsQxOJ3T57k7RFe35SUwWMf7dsbDZks1uOmw4AecB/JMDj3v/w==} - engines: {node: '>=8.15'} + which-pm@2.0.0: dependencies: load-yaml-file: 0.2.0 path-exists: 4.0.0 - dev: true - /which-typed-array@1.1.18: - resolution: {integrity: sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==} - engines: {node: '>= 0.4'} + which-typed-array@1.1.18: dependencies: available-typed-arrays: 1.0.7 call-bind: 1.0.8 @@ -6344,146 +7208,73 @@ packages: for-each: 0.3.3 gopd: 1.2.0 has-tostringtag: 1.0.2 - dev: true - /which@1.3.1: - resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} - hasBin: true + which@1.3.1: dependencies: isexe: 2.0.0 - dev: true - /which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true + which@2.0.2: dependencies: isexe: 2.0.0 - dev: true - /why-is-node-running@2.2.2: - resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==} - engines: {node: '>=8'} - hasBin: true + why-is-node-running@2.2.2: dependencies: siginfo: 2.0.0 stackback: 0.0.2 - dev: true - /word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - dev: true + word-wrap@1.2.5: {} - /wrap-ansi@6.2.0: - resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} - engines: {node: '>=8'} + wrap-ansi@6.2.0: dependencies: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: true - /wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: true - /wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - dev: true + wrappy@1.0.2: {} - /ws@8.11.0: - resolution: {integrity: sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - dev: true + ws@8.11.0: {} - /xml-name-validator@4.0.0: - resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} - engines: {node: '>=12'} - dev: true + xml-name-validator@4.0.0: {} - /xml2js@0.6.2: - resolution: {integrity: sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==} - engines: {node: '>=4.0.0'} + xml2js@0.6.2: dependencies: sax: 1.2.1 xmlbuilder: 11.0.1 - dev: true - /xmlbuilder@11.0.1: - resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} - engines: {node: '>=4.0'} - dev: true + xmlbuilder@11.0.1: {} - /xmlchars@2.2.0: - resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} - dev: true + xmlchars@2.2.0: {} - /y18n@4.0.3: - resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} - dev: true + y18n@4.0.3: {} - /y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - dev: true + y18n@5.0.8: {} - /yallist@2.1.2: - resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==} - dev: true + yallist@2.1.2: {} - /yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - dev: true + yallist@3.1.1: {} - /yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - dev: true + yallist@4.0.0: {} - /yaml@1.10.2: - resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} - engines: {node: '>= 6'} - dev: true + yaml@1.10.2: {} - /yaml@2.1.3: - resolution: {integrity: sha512-AacA8nRULjKMX2DvWvOAdBZMOfQlypSFkjcOcu9FalllIDJ1kvlREzcdIZmidQUqqeMv7jorHjq2HlLv/+c2lg==} - engines: {node: '>= 14'} - dev: true + yaml@2.1.3: {} - /yargs-parser@18.1.3: - resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} - engines: {node: '>=6'} + yargs-parser@18.1.3: dependencies: camelcase: 5.3.1 decamelize: 1.2.0 - dev: true - /yargs-parser@20.2.9: - resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} - engines: {node: '>=10'} - dev: true + yargs-parser@20.2.9: {} - /yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - dev: true + yargs-parser@21.1.1: {} - /yargs@15.4.1: - resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} - engines: {node: '>=8'} + yargs@15.4.1: dependencies: cliui: 6.0.0 decamelize: 1.2.0 @@ -6496,11 +7287,8 @@ packages: which-module: 2.0.0 y18n: 4.0.3 yargs-parser: 18.1.3 - dev: true - /yargs@16.2.0: - resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} - engines: {node: '>=10'} + yargs@16.2.0: dependencies: cliui: 7.0.4 escalade: 3.1.1 @@ -6509,11 +7297,8 @@ packages: string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 20.2.9 - dev: true - /yargs@17.6.2: - resolution: {integrity: sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==} - engines: {node: '>=12'} + yargs@17.6.2: dependencies: cliui: 8.0.1 escalade: 3.1.1 @@ -6522,20 +7307,9 @@ packages: string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 21.1.1 - dev: true - - /yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - dev: true - /yocto-queue@1.0.0: - resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} - engines: {node: '>=12.20'} - dev: true + yocto-queue@0.1.0: {} - /zod@3.19.1: - resolution: {integrity: sha512-LYjZsEDhCdYET9ikFu6dVPGp2YH9DegXjdJToSzD9rO6fy4qiRYFoyEYwps88OseJlPyl2NOe2iJuhEhL7IpEA==} - dev: false + yocto-queue@1.0.0: {} -publishDirectory: dist + zod@3.19.1: {} From 2faa3844dcb8670b92c095e58cbfe9485930b6fc Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 17 Jan 2025 18:03:55 +0100 Subject: [PATCH 37/58] Add JS docs --- .../aws-lambda/create-app-register.ts | 17 ++++++++++++++++ .../fetch-api/create-app-register-handler.ts | 20 +++++++++++++++++++ .../next/create-app-register-handler.ts | 14 ++++++++++++- 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/handlers/aws-lambda/create-app-register.ts b/src/handlers/aws-lambda/create-app-register.ts index 3e9b7b3b..639e3d7d 100644 --- a/src/handlers/aws-lambda/create-app-register.ts +++ b/src/handlers/aws-lambda/create-app-register.ts @@ -18,6 +18,23 @@ export const createRegisterHandlerResponseBody = ( export type CreateAppRegisterHandlerOptions = GenericCreateAppRegisterHandlerOptions; +/** + * Returns API route handler for AWS Lambda HTTP triggered events + * (created by Amazon API Gateway, Lambda Function URL) + * that use signature: (event: APIGatewayProxyEventV2, context: Context) => APIGatewayProxyResultV2 + * + * Handler is for register endpoint that is called by Saleor when installing the app + * + * It verifies the request and stores `app_token` from Saleor + * in APL and along with all required AuthData fields (jwks, saleorApiUrl, ...) + * + * **Recommended path**: `/api/register` + * (configured in manifest handler) + * + * To learn more check Saleor docs + * @see {@link https://docs.saleor.io/developer/extending/apps/architecture/app-requirements#register-url} + * @see {@link https://www.npmjs.com/package/@types/aws-lambda} + * */ export const createAppRegisterHandler = (config: CreateAppRegisterHandlerOptions): AWSLambdaHandler => async (event: APIGatewayProxyEventV2, context: Context) => { diff --git a/src/handlers/fetch-api/create-app-register-handler.ts b/src/handlers/fetch-api/create-app-register-handler.ts index 49641fa0..36be09f3 100644 --- a/src/handlers/fetch-api/create-app-register-handler.ts +++ b/src/handlers/fetch-api/create-app-register-handler.ts @@ -16,6 +16,26 @@ export const createRegisterHandlerResponseBody = ( export type CreateAppRegisterHandlerOptions = GenericCreateAppRegisterHandlerOptions; +/** + * Returns API route handler for Web API compatible request handlers + * (examples: Next.js app router, hono, deno, etc.) + * that use signature: (req: Request) => Response + * where Request and Response are Fetch API objects + * + * Handler is for register endpoint that is called by Saleor when installing the app + * + * It verifies the request and stores `app_token` from Saleor + * in APL and along with all required AuthData fields (jwks, saleorApiUrl, ...) + * + * **Recommended path**: `/api/register` + * (configured in manifest handler) + * + * To learn more check Saleor docs + * @see {@link https://docs.saleor.io/developer/extending/apps/architecture/app-requirements#register-url} + * + * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Response} + * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Request} + * */ export const createAppRegisterHandler = (config: CreateAppRegisterHandlerOptions): WebApiHandler => async (req: Request) => { diff --git a/src/handlers/next/create-app-register-handler.ts b/src/handlers/next/create-app-register-handler.ts index e17ff6e6..0fb43428 100644 --- a/src/handlers/next/create-app-register-handler.ts +++ b/src/handlers/next/create-app-register-handler.ts @@ -19,10 +19,22 @@ export const createRegisterHandlerResponseBody = ( error, }); -// Request type is from retest (Next.js interface) export type CreateAppRegisterHandlerOptions = GenericCreateAppRegisterHandlerOptions; +/** + * Returns API route handler for **Next.js pages router** + * for register endpoint that is called by Saleor when installing the app + * + * It verifies the request and stores `app_token` from Saleor + * in APL and along with all required AuthData fields (jwks, saleorApiUrl, ...) + * + * **Recommended path**: `/api/register` + * (configured in manifest handler) + * + * To learn more check Saleor docs + * @see {@link https://docs.saleor.io/developer/extending/apps/architecture/app-requirements#register-url} + * */ export const createAppRegisterHandler = (config: CreateAppRegisterHandlerOptions) => async (req: NextApiRequest, res: NextApiResponse) => { From 0d01b295952896441c4d7fd679c81c6677bb23fa Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 17 Jan 2025 18:09:05 +0100 Subject: [PATCH 38/58] Cleanup tsconfig --- tsconfig.json | 104 +++++--------------------------------------------- 1 file changed, 10 insertions(+), 94 deletions(-) diff --git a/tsconfig.json b/tsconfig.json index 90fe2d82..4863e398 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,98 +1,14 @@ { "compilerOptions": { - /* Visit https://aka.ms/tsconfig to read more about this file */ - /* Projects */ - // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ - // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ - // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ - // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ - // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ - // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - /* Language and Environment */ - "target": "ES2021" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, - "lib": [ - "dom", - "ES2021" - ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */, - "jsx": "react" /* Specify what JSX code is generated. */, - // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ - // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ - // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ - // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ - // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ - // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - "useDefineForClassFields": false /* Don't Emit ECMAScript-standard-compliant class fields. - we can use class field initializers, after constructor is run */, - // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ - /* Modules */ - "module": "commonjs" /* Specify what module code is generated. */, - // "rootDir": "./", /* Specify the root folder within your source files. */ - // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ - // "types": [], /* Specify type package names to be included without being referenced in a source file. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ - "resolveJsonModule": true /* Enable importing .json files. */, - // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ - /* JavaScript Support */ - // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ - // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ - /* Emit */ - // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ - // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - // "outDir": "./", /* Specify an output folder for all emitted files. */ - // "removeComments": true, /* Disable emitting comments. */ - // "noEmit": true, /* Disable emitting files from a compilation. */ - // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ - // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ - // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ - // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ - // "newLine": "crlf", /* Set the newline character for emitting files. */ - // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ - // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ - // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ - // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ - // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ - /* Interop Constraints */ - // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, - // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, - /* Type Checking */ - "strict": true /* Enable all strict type-checking options. */, - // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ - // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ - // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ - // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ - // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ - // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ - // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ - // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - /* Completeness */ - // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ + "target": "ES2021", + "lib": ["dom", "ES2021"], + "jsx": "react", + "useDefineForClassFields": false, + "module": "commonjs", + "resolveJsonModule": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true } } From 2d6bbfb9eba9059bf8a4f8f335c957b226e9597c Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 17 Jan 2025 18:22:46 +0100 Subject: [PATCH 39/58] Reorganize folder structure, add actions folder, move handlers to /platforms --- package.json | 5 +++++ src/handlers/actions/index.ts | 1 + .../register-action-handler.ts | 19 ++++++++++--------- .../aws-lambda/create-app-register.ts | 5 +++-- .../aws-lambda/platform-adapter.ts | 2 +- .../fetch-api/create-app-register-handler.ts | 5 +++-- .../fetch-api/create-manifest-handler.ts | 4 ++-- .../fetch-api/create-protected-handler.ts | 11 ++++++----- .../{ => platforms}/fetch-api/index.ts | 0 .../fetch-api/platform-adapter.ts | 2 +- .../fetch-api/process-protected-handler.ts | 16 ++++++++-------- .../saleor-webhooks/process-saleor-webhook.ts | 14 +++++++------- .../saleor-webhooks/saleor-async-webhook.ts | 3 ++- .../saleor-webhooks/saleor-sync-webhook.ts | 5 +++-- .../saleor-webhooks/saleor-webhook.ts | 13 +++++++------ .../next/create-app-register-handler.test.ts | 5 +++-- .../next/create-app-register-handler.ts | 5 +++-- .../next/create-manifest-handler.test.ts | 3 ++- .../next/create-manifest-handler.ts | 6 +++--- .../next/create-protected-handler.ts | 11 ++++++----- src/handlers/{ => platforms}/next/index.ts | 4 ++-- .../{ => platforms}/next/platform-adapter.ts | 2 +- .../next/process-protected-handler.test.ts | 11 ++++++----- .../next/process-protected-handler.ts | 16 ++++++++-------- .../process-saleor-webhook.test.ts | 0 .../saleor-webhooks/process-saleor-webhook.ts | 16 ++++++++-------- .../saleor-async-webhook.test.ts | 5 +++-- .../saleor-webhooks/saleor-async-webhook.ts | 3 ++- .../saleor-sync-webhook.test.ts | 3 ++- .../saleor-webhooks/saleor-sync-webhook.ts | 5 +++-- .../next/saleor-webhooks/saleor-webhook.ts | 13 +++++++------ src/handlers/shared/adapter-middleware.ts | 5 +++-- tsconfig.json | 7 ++++++- tsup.config.ts | 12 ++++++++---- 34 files changed, 135 insertions(+), 102 deletions(-) create mode 100644 src/handlers/actions/index.ts rename src/handlers/{shared => actions}/register-action-handler.ts (96%) rename src/handlers/{ => platforms}/aws-lambda/create-app-register.ts (90%) rename src/handlers/{ => platforms}/aws-lambda/platform-adapter.ts (95%) rename src/handlers/{ => platforms}/fetch-api/create-app-register-handler.ts (90%) rename src/handlers/{ => platforms}/fetch-api/create-manifest-handler.ts (84%) rename src/handlers/{ => platforms}/fetch-api/create-protected-handler.ts (81%) rename src/handlers/{ => platforms}/fetch-api/index.ts (100%) rename src/handlers/{ => platforms}/fetch-api/platform-adapter.ts (94%) rename src/handlers/{ => platforms}/fetch-api/process-protected-handler.ts (90%) rename src/handlers/{ => platforms}/fetch-api/saleor-webhooks/process-saleor-webhook.ts (90%) rename src/handlers/{ => platforms}/fetch-api/saleor-webhooks/saleor-async-webhook.ts (96%) rename src/handlers/{ => platforms}/fetch-api/saleor-webhooks/saleor-sync-webhook.ts (86%) rename src/handlers/{ => platforms}/fetch-api/saleor-webhooks/saleor-webhook.ts (94%) rename src/handlers/{ => platforms}/next/create-app-register-handler.test.ts (98%) rename src/handlers/{ => platforms}/next/create-app-register-handler.ts (89%) rename src/handlers/{ => platforms}/next/create-manifest-handler.test.ts (96%) rename src/handlers/{ => platforms}/next/create-manifest-handler.ts (89%) rename src/handlers/{ => platforms}/next/create-protected-handler.ts (83%) rename src/handlers/{ => platforms}/next/index.ts (77%) rename src/handlers/{ => platforms}/next/platform-adapter.ts (94%) rename src/handlers/{ => platforms}/next/process-protected-handler.test.ts (95%) rename src/handlers/{ => platforms}/next/process-protected-handler.ts (90%) rename src/handlers/{ => platforms}/next/saleor-webhooks/process-saleor-webhook.test.ts (100%) rename src/handlers/{ => platforms}/next/saleor-webhooks/process-saleor-webhook.ts (92%) rename src/handlers/{ => platforms}/next/saleor-webhooks/saleor-async-webhook.test.ts (98%) rename src/handlers/{ => platforms}/next/saleor-webhooks/saleor-async-webhook.ts (96%) rename src/handlers/{ => platforms}/next/saleor-webhooks/saleor-sync-webhook.test.ts (97%) rename src/handlers/{ => platforms}/next/saleor-webhooks/saleor-sync-webhook.ts (86%) rename src/handlers/{ => platforms}/next/saleor-webhooks/saleor-webhook.ts (93%) diff --git a/package.json b/package.json index 3789560d..31f21456 100644 --- a/package.json +++ b/package.json @@ -154,6 +154,11 @@ "import": "./handlers/fetch-api/index.mjs", "require": "./handlers/fetch-api/index.js" }, + "./handlers/actions": { + "types": "./handlers/actions/index.d.ts", + "import": "./handlers/actions/index.mjs", + "require": "./handlers/actions/index.js" + }, "./handlers/shared": { "types": "./handlers/shared/index.d.ts", "import": "./handlers/shared/index.mjs", diff --git a/src/handlers/actions/index.ts b/src/handlers/actions/index.ts new file mode 100644 index 00000000..c74e02b8 --- /dev/null +++ b/src/handlers/actions/index.ts @@ -0,0 +1 @@ +export * from "./register-action-handler"; diff --git a/src/handlers/shared/register-action-handler.ts b/src/handlers/actions/register-action-handler.ts similarity index 96% rename from src/handlers/shared/register-action-handler.ts rename to src/handlers/actions/register-action-handler.ts index 1d526516..017938f7 100644 --- a/src/handlers/shared/register-action-handler.ts +++ b/src/handlers/actions/register-action-handler.ts @@ -1,18 +1,19 @@ /* eslint-disable max-classes-per-file */ -import { APL, AuthData } from "../../APL"; -import { SALEOR_API_URL_HEADER, SALEOR_DOMAIN_HEADER } from "../../const"; -import { createDebug } from "../../debug"; -import { fetchRemoteJwks } from "../../fetch-remote-jwks"; -import { getAppId } from "../../get-app-id"; -import { HasAPL } from "../../saleor-app"; -import { PlatformAdapterMiddleware } from "./adapter-middleware"; +import { APL, AuthData } from "@/APL"; +import { SALEOR_API_URL_HEADER, SALEOR_DOMAIN_HEADER } from "@/const"; +import { createDebug } from "@/debug"; +import { fetchRemoteJwks } from "@/fetch-remote-jwks"; +import { getAppId } from "@/get-app-id"; +import { HasAPL } from "@/saleor-app"; + +import { PlatformAdapterMiddleware } from "../shared/adapter-middleware"; import { ActionHandlerInterface, ActionHandlerResult, PlatformAdapterInterface, ResultStatusCodes, -} from "./generic-adapter-use-case-types"; -import { validateAllowSaleorUrls } from "./validate-allow-saleor-urls"; +} from "../shared/generic-adapter-use-case-types"; +import { validateAllowSaleorUrls } from "../shared/validate-allow-saleor-urls"; const debug = createDebug("createAppRegisterHandler"); diff --git a/src/handlers/aws-lambda/create-app-register.ts b/src/handlers/platforms/aws-lambda/create-app-register.ts similarity index 90% rename from src/handlers/aws-lambda/create-app-register.ts rename to src/handlers/platforms/aws-lambda/create-app-register.ts index 639e3d7d..3a7bfc6a 100644 --- a/src/handlers/aws-lambda/create-app-register.ts +++ b/src/handlers/platforms/aws-lambda/create-app-register.ts @@ -1,10 +1,11 @@ import { APIGatewayProxyEventV2, Context } from "aws-lambda"; -import { GenericCreateAppRegisterHandlerOptions } from "../shared/create-app-register-handler-types"; import { RegisterActionHandler, RegisterHandlerResponseBody, -} from "../shared/register-action-handler"; +} from "@/handlers/actions/register-action-handler"; +import { GenericCreateAppRegisterHandlerOptions } from "@/handlers/shared/create-app-register-handler-types"; + import { AwsLambdaAdapter, AWSLambdaHandler, AwsLambdaHandlerInput } from "./platform-adapter"; export const createRegisterHandlerResponseBody = ( diff --git a/src/handlers/aws-lambda/platform-adapter.ts b/src/handlers/platforms/aws-lambda/platform-adapter.ts similarity index 95% rename from src/handlers/aws-lambda/platform-adapter.ts rename to src/handlers/platforms/aws-lambda/platform-adapter.ts index fa61b215..749722ef 100644 --- a/src/handlers/aws-lambda/platform-adapter.ts +++ b/src/handlers/platforms/aws-lambda/platform-adapter.ts @@ -4,7 +4,7 @@ import { ActionHandlerResult, HTTPMethod, PlatformAdapterInterface, -} from "../shared/generic-adapter-use-case-types"; +} from "@/handlers/shared/generic-adapter-use-case-types"; export type AwsLambdaHandlerInput = APIGatewayProxyEventV2; export type AWSLambdaHandler = ( diff --git a/src/handlers/fetch-api/create-app-register-handler.ts b/src/handlers/platforms/fetch-api/create-app-register-handler.ts similarity index 90% rename from src/handlers/fetch-api/create-app-register-handler.ts rename to src/handlers/platforms/fetch-api/create-app-register-handler.ts index 36be09f3..3781fd82 100644 --- a/src/handlers/fetch-api/create-app-register-handler.ts +++ b/src/handlers/platforms/fetch-api/create-app-register-handler.ts @@ -1,8 +1,9 @@ -import { GenericCreateAppRegisterHandlerOptions } from "../shared/create-app-register-handler-types"; import { RegisterActionHandler, RegisterHandlerResponseBody, -} from "../shared/register-action-handler"; +} from "@/handlers/actions/register-action-handler"; +import { GenericCreateAppRegisterHandlerOptions } from "@/handlers/shared/create-app-register-handler-types"; + import { WebApiAdapter, WebApiHandler, WebApiHandlerInput } from "./platform-adapter"; export const createRegisterHandlerResponseBody = ( diff --git a/src/handlers/fetch-api/create-manifest-handler.ts b/src/handlers/platforms/fetch-api/create-manifest-handler.ts similarity index 84% rename from src/handlers/fetch-api/create-manifest-handler.ts rename to src/handlers/platforms/fetch-api/create-manifest-handler.ts index fe554a76..ec514aae 100644 --- a/src/handlers/fetch-api/create-manifest-handler.ts +++ b/src/handlers/platforms/fetch-api/create-manifest-handler.ts @@ -1,5 +1,5 @@ -import { getBaseUrlFetchAPI, getSaleorHeadersFetchAPI } from "../../headers"; -import { AppManifest } from "../../types"; +import { getBaseUrlFetchAPI, getSaleorHeadersFetchAPI } from "@/headers"; +import { AppManifest } from "@/types"; export type CreateManifestHandlerOptions = { manifestFactory(context: { diff --git a/src/handlers/fetch-api/create-protected-handler.ts b/src/handlers/platforms/fetch-api/create-protected-handler.ts similarity index 81% rename from src/handlers/fetch-api/create-protected-handler.ts rename to src/handlers/platforms/fetch-api/create-protected-handler.ts index e035cd0a..4b17afb3 100644 --- a/src/handlers/fetch-api/create-protected-handler.ts +++ b/src/handlers/platforms/fetch-api/create-protected-handler.ts @@ -1,8 +1,9 @@ -import { APL } from "../../APL"; -import { createDebug } from "../../debug"; -import { Permission } from "../../types"; -import { ProtectedHandlerErrorCodeMap } from "../shared/protected-handler"; -import { ProtectedHandlerContext } from "../shared/protected-handler-context"; +import { APL } from "@/APL"; +import { createDebug } from "@/debug"; +import { ProtectedHandlerErrorCodeMap } from "@/handlers/shared/protected-handler"; +import { ProtectedHandlerContext } from "@/handlers/shared/protected-handler-context"; +import { Permission } from "@/types"; + import { processSaleorProtectedHandler, ProtectedHandlerError } from "./process-protected-handler"; const debug = createDebug("WebAPI:ProtectedHandler"); diff --git a/src/handlers/fetch-api/index.ts b/src/handlers/platforms/fetch-api/index.ts similarity index 100% rename from src/handlers/fetch-api/index.ts rename to src/handlers/platforms/fetch-api/index.ts diff --git a/src/handlers/fetch-api/platform-adapter.ts b/src/handlers/platforms/fetch-api/platform-adapter.ts similarity index 94% rename from src/handlers/fetch-api/platform-adapter.ts rename to src/handlers/platforms/fetch-api/platform-adapter.ts index 83273a76..b13f7367 100644 --- a/src/handlers/fetch-api/platform-adapter.ts +++ b/src/handlers/platforms/fetch-api/platform-adapter.ts @@ -1,7 +1,7 @@ import { ActionHandlerResult, PlatformAdapterInterface, -} from "../shared/generic-adapter-use-case-types"; +} from "@/handlers/shared/generic-adapter-use-case-types"; export type WebApiHandlerInput = Request; export type WebApiHandler = (req: Request) => Response | Promise; diff --git a/src/handlers/fetch-api/process-protected-handler.ts b/src/handlers/platforms/fetch-api/process-protected-handler.ts similarity index 90% rename from src/handlers/fetch-api/process-protected-handler.ts rename to src/handlers/platforms/fetch-api/process-protected-handler.ts index 8edb38e5..0f2dd4cb 100644 --- a/src/handlers/fetch-api/process-protected-handler.ts +++ b/src/handlers/platforms/fetch-api/process-protected-handler.ts @@ -1,13 +1,13 @@ import { SpanKind, SpanStatusCode } from "@opentelemetry/api"; -import { APL } from "../../APL"; -import { createDebug } from "../../debug"; -import { getBaseUrlFetchAPI, getSaleorHeadersFetchAPI } from "../../headers"; -import { getOtelTracer } from "../../open-telemetry"; -import { Permission } from "../../types"; -import { extractUserFromJwt } from "../../util/extract-user-from-jwt"; -import { verifyJWT } from "../../verify-jwt"; -import { ProtectedHandlerContext } from "../shared/protected-handler-context"; +import { APL } from "@/APL"; +import { createDebug } from "@/debug"; +import { ProtectedHandlerContext } from "@/handlers/shared/protected-handler-context"; +import { getBaseUrlFetchAPI, getSaleorHeadersFetchAPI } from "@/headers"; +import { getOtelTracer } from "@/open-telemetry"; +import { Permission } from "@/types"; +import { extractUserFromJwt } from "@/util/extract-user-from-jwt"; +import { verifyJWT } from "@/verify-jwt"; const debug = createDebug("WebAPI:processProtectedHandler"); diff --git a/src/handlers/fetch-api/saleor-webhooks/process-saleor-webhook.ts b/src/handlers/platforms/fetch-api/saleor-webhooks/process-saleor-webhook.ts similarity index 90% rename from src/handlers/fetch-api/saleor-webhooks/process-saleor-webhook.ts rename to src/handlers/platforms/fetch-api/saleor-webhooks/process-saleor-webhook.ts index 528642a4..b4d14336 100644 --- a/src/handlers/fetch-api/saleor-webhooks/process-saleor-webhook.ts +++ b/src/handlers/platforms/fetch-api/saleor-webhooks/process-saleor-webhook.ts @@ -1,10 +1,10 @@ -import { APL } from "../../../APL"; -import { createDebug } from "../../../debug"; -import { fetchRemoteJwks } from "../../../fetch-remote-jwks"; -import { getBaseUrlFetchAPI, getSaleorHeadersFetchAPI } from "../../../headers"; -import { parseSchemaVersion } from "../../../util"; -import { verifySignatureWithJwks } from "../../../verify-signature"; -import { WebhookContext, WebhookError } from "../../shared/process-saleor-webhook"; +import { APL } from "@/APL"; +import { createDebug } from "@/debug"; +import { fetchRemoteJwks } from "@/fetch-remote-jwks"; +import { WebhookContext, WebhookError } from "@/handlers/shared/process-saleor-webhook"; +import { getBaseUrlFetchAPI, getSaleorHeadersFetchAPI } from "@/headers"; +import { parseSchemaVersion } from "@/util"; +import { verifySignatureWithJwks } from "@/verify-signature"; const debug = createDebug("WebAPI:processSaleorWebhook"); diff --git a/src/handlers/fetch-api/saleor-webhooks/saleor-async-webhook.ts b/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-async-webhook.ts similarity index 96% rename from src/handlers/fetch-api/saleor-webhooks/saleor-async-webhook.ts rename to src/handlers/platforms/fetch-api/saleor-webhooks/saleor-async-webhook.ts index 71a191cb..dc84eeaf 100644 --- a/src/handlers/fetch-api/saleor-webhooks/saleor-async-webhook.ts +++ b/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-async-webhook.ts @@ -1,6 +1,7 @@ import { ASTNode } from "graphql"; -import { AsyncWebhookEventType } from "../../../types"; +import { AsyncWebhookEventType } from "@/types"; + import { SaleorWebApiWebhook, SaleorWebhookHandler, diff --git a/src/handlers/fetch-api/saleor-webhooks/saleor-sync-webhook.ts b/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-sync-webhook.ts similarity index 86% rename from src/handlers/fetch-api/saleor-webhooks/saleor-sync-webhook.ts rename to src/handlers/platforms/fetch-api/saleor-webhooks/saleor-sync-webhook.ts index d3cc2e5a..1b993da8 100644 --- a/src/handlers/fetch-api/saleor-webhooks/saleor-sync-webhook.ts +++ b/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-sync-webhook.ts @@ -1,5 +1,6 @@ -import { SyncWebhookEventType } from "../../../types"; -import { buildSyncWebhookResponsePayload } from "../../shared/sync-webhook-response-builder"; +import { buildSyncWebhookResponsePayload } from "@/handlers/shared/sync-webhook-response-builder"; +import { SyncWebhookEventType } from "@/types"; + import { SaleorWebApiWebhook, SaleorWebhookHandler, diff --git a/src/handlers/fetch-api/saleor-webhooks/saleor-webhook.ts b/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-webhook.ts similarity index 94% rename from src/handlers/fetch-api/saleor-webhooks/saleor-webhook.ts rename to src/handlers/platforms/fetch-api/saleor-webhooks/saleor-webhook.ts index 9d5a1709..d9352e0a 100644 --- a/src/handlers/fetch-api/saleor-webhooks/saleor-webhook.ts +++ b/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-webhook.ts @@ -1,11 +1,12 @@ import { ASTNode } from "graphql"; -import { APL } from "../../../APL"; -import { createDebug } from "../../../debug"; -import { gqlAstToString } from "../../../gql-ast-to-string"; -import { AsyncWebhookEventType, SyncWebhookEventType, WebhookManifest } from "../../../types"; -import { WebhookContext, WebhookError } from "../../shared/process-saleor-webhook"; -import { WebhookErrorCodeMap } from "../../shared/saleor-webhook"; +import { APL } from "@/APL"; +import { createDebug } from "@/debug"; +import { gqlAstToString } from "@/gql-ast-to-string"; +import { WebhookContext, WebhookError } from "@/handlers/shared/process-saleor-webhook"; +import { WebhookErrorCodeMap } from "@/handlers/shared/saleor-webhook"; +import { AsyncWebhookEventType, SyncWebhookEventType, WebhookManifest } from "@/types"; + import { processSaleorWebhook } from "./process-saleor-webhook"; const debug = createDebug("SaleorWebhook"); diff --git a/src/handlers/next/create-app-register-handler.test.ts b/src/handlers/platforms/next/create-app-register-handler.test.ts similarity index 98% rename from src/handlers/next/create-app-register-handler.test.ts rename to src/handlers/platforms/next/create-app-register-handler.test.ts index 6298a527..8d792f09 100644 --- a/src/handlers/next/create-app-register-handler.test.ts +++ b/src/handlers/platforms/next/create-app-register-handler.test.ts @@ -1,8 +1,9 @@ import { createMocks } from "node-mocks-http"; import { beforeEach, describe, expect, it, Mock, vi } from "vitest"; -import { APL, AuthData } from "../../APL"; -import { MockAPL } from "../../test-utils/mock-apl"; +import { APL, AuthData } from "@/APL"; +import { MockAPL } from "@/test-utils/mock-apl"; + import { createAppRegisterHandler } from "./create-app-register-handler"; const mockJwksValue = "{}"; diff --git a/src/handlers/next/create-app-register-handler.ts b/src/handlers/platforms/next/create-app-register-handler.ts similarity index 89% rename from src/handlers/next/create-app-register-handler.ts rename to src/handlers/platforms/next/create-app-register-handler.ts index 0fb43428..5b1b27cb 100644 --- a/src/handlers/next/create-app-register-handler.ts +++ b/src/handlers/platforms/next/create-app-register-handler.ts @@ -1,10 +1,11 @@ import { NextApiRequest, NextApiResponse } from "next"; -import { GenericCreateAppRegisterHandlerOptions } from "../shared/create-app-register-handler-types"; import { RegisterActionHandler, RegisterHandlerResponseBody, -} from "../shared/register-action-handler"; +} from "@/handlers/actions/register-action-handler"; +import { GenericCreateAppRegisterHandlerOptions } from "@/handlers/shared/create-app-register-handler-types"; + import { NextJsAdapter, NextJsHandlerInput } from "./platform-adapter"; // Re-export types for backwards compatibility diff --git a/src/handlers/next/create-manifest-handler.test.ts b/src/handlers/platforms/next/create-manifest-handler.test.ts similarity index 96% rename from src/handlers/next/create-manifest-handler.test.ts rename to src/handlers/platforms/next/create-manifest-handler.test.ts index f9caa04b..5fe18733 100644 --- a/src/handlers/next/create-manifest-handler.test.ts +++ b/src/handlers/platforms/next/create-manifest-handler.test.ts @@ -1,7 +1,8 @@ import { createMocks } from "node-mocks-http"; import { describe, expect, it } from "vitest"; -import { AppManifest } from "../../types"; +import { AppManifest } from "@/types"; + import { createManifestHandler } from "./create-manifest-handler"; describe("createManifestHandler", () => { diff --git a/src/handlers/next/create-manifest-handler.ts b/src/handlers/platforms/next/create-manifest-handler.ts similarity index 89% rename from src/handlers/next/create-manifest-handler.ts rename to src/handlers/platforms/next/create-manifest-handler.ts index aceedd6c..5fff0717 100644 --- a/src/handlers/next/create-manifest-handler.ts +++ b/src/handlers/platforms/next/create-manifest-handler.ts @@ -1,8 +1,8 @@ import { NextApiHandler, NextApiRequest } from "next"; -import { createDebug } from "../../debug"; -import { getBaseUrl, getSaleorHeaders } from "../../headers"; -import { AppManifest } from "../../types"; +import { createDebug } from "@/debug"; +import { getBaseUrl, getSaleorHeaders } from "@/headers"; +import { AppManifest } from "@/types"; export type CreateManifestHandlerOptions = { manifestFactory(context: { diff --git a/src/handlers/next/create-protected-handler.ts b/src/handlers/platforms/next/create-protected-handler.ts similarity index 83% rename from src/handlers/next/create-protected-handler.ts rename to src/handlers/platforms/next/create-protected-handler.ts index f8610569..9bc76b92 100644 --- a/src/handlers/next/create-protected-handler.ts +++ b/src/handlers/platforms/next/create-protected-handler.ts @@ -1,10 +1,11 @@ import { NextApiHandler, NextApiRequest, NextApiResponse } from "next"; -import { APL } from "../../APL"; -import { createDebug } from "../../debug"; -import { Permission } from "../../types"; -import { ProtectedHandlerErrorCodeMap } from "../shared/protected-handler"; -import { ProtectedHandlerContext } from "../shared/protected-handler-context"; +import { APL } from "@/APL"; +import { createDebug } from "@/debug"; +import { ProtectedHandlerErrorCodeMap } from "@/handlers/shared/protected-handler"; +import { ProtectedHandlerContext } from "@/handlers/shared/protected-handler-context"; +import { Permission } from "@/types"; + import { processSaleorProtectedHandler, ProtectedHandlerError } from "./process-protected-handler"; const debug = createDebug("ProtectedHandler"); diff --git a/src/handlers/next/index.ts b/src/handlers/platforms/next/index.ts similarity index 77% rename from src/handlers/next/index.ts rename to src/handlers/platforms/next/index.ts index 5480b408..3bf56a88 100644 --- a/src/handlers/next/index.ts +++ b/src/handlers/platforms/next/index.ts @@ -1,6 +1,6 @@ // Re-export to avoid breaking changes -export * from "../shared/protected-handler-context"; -export * from "../shared/sync-webhook-response-builder"; +export * from "../../shared/protected-handler-context"; +export * from "../../shared/sync-webhook-response-builder"; export * from "./create-app-register-handler"; export * from "./create-manifest-handler"; export * from "./create-protected-handler"; diff --git a/src/handlers/next/platform-adapter.ts b/src/handlers/platforms/next/platform-adapter.ts similarity index 94% rename from src/handlers/next/platform-adapter.ts rename to src/handlers/platforms/next/platform-adapter.ts index 6222b64b..945712e3 100644 --- a/src/handlers/next/platform-adapter.ts +++ b/src/handlers/platforms/next/platform-adapter.ts @@ -3,7 +3,7 @@ import { NextApiRequest, NextApiResponse } from "next"; import { ActionHandlerResult, PlatformAdapterInterface, -} from "../shared/generic-adapter-use-case-types"; +} from "@/handlers/shared/generic-adapter-use-case-types"; export type NextJsHandlerInput = NextApiRequest; export type NextJsHandler = ( diff --git a/src/handlers/next/process-protected-handler.test.ts b/src/handlers/platforms/next/process-protected-handler.test.ts similarity index 95% rename from src/handlers/next/process-protected-handler.test.ts rename to src/handlers/platforms/next/process-protected-handler.test.ts index 69c3e221..ede2966d 100644 --- a/src/handlers/next/process-protected-handler.test.ts +++ b/src/handlers/platforms/next/process-protected-handler.test.ts @@ -2,9 +2,10 @@ import { NextApiRequest } from "next/types"; import { createMocks } from "node-mocks-http"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { getAppId } from "../../get-app-id"; -import { MockAPL } from "../../test-utils/mock-apl"; -import { verifyJWT } from "../../verify-jwt"; +import { getAppId } from "@/get-app-id"; +import { MockAPL } from "@/test-utils/mock-apl"; +import { verifyJWT } from "@/verify-jwt"; + import { processSaleorProtectedHandler } from "./process-protected-handler"; const validToken = @@ -12,12 +13,12 @@ const validToken = const validAppId = "QXBwOjI3NQ=="; -vi.mock("./../../get-app-id", () => ({ +vi.mock("./@/get-app-id", () => ({ // eslint-disable-next-line @typescript-eslint/no-unused-vars getAppId: vi.fn(), })); -vi.mock("./../../verify-jwt", () => ({ +vi.mock("./@/verify-jwt", () => ({ // eslint-disable-next-line @typescript-eslint/no-unused-vars verifyJWT: vi.fn(), })); diff --git a/src/handlers/next/process-protected-handler.ts b/src/handlers/platforms/next/process-protected-handler.ts similarity index 90% rename from src/handlers/next/process-protected-handler.ts rename to src/handlers/platforms/next/process-protected-handler.ts index 020763be..ff55be09 100644 --- a/src/handlers/next/process-protected-handler.ts +++ b/src/handlers/platforms/next/process-protected-handler.ts @@ -1,14 +1,14 @@ import { SpanKind, SpanStatusCode } from "@opentelemetry/api"; import { NextApiRequest } from "next"; -import { APL } from "../../APL"; -import { createDebug } from "../../debug"; -import { getBaseUrl, getSaleorHeaders } from "../../headers"; -import { getOtelTracer } from "../../open-telemetry"; -import { Permission } from "../../types"; -import { extractUserFromJwt } from "../../util/extract-user-from-jwt"; -import { verifyJWT } from "../../verify-jwt"; -import { ProtectedHandlerContext } from "../shared/protected-handler-context"; +import { APL } from "@/APL"; +import { createDebug } from "@/debug"; +import { ProtectedHandlerContext } from "@/handlers/shared/protected-handler-context"; +import { getBaseUrl, getSaleorHeaders } from "@/headers"; +import { getOtelTracer } from "@/open-telemetry"; +import { Permission } from "@/types"; +import { extractUserFromJwt } from "@/util/extract-user-from-jwt"; +import { verifyJWT } from "@/verify-jwt"; const debug = createDebug("processProtectedHandler"); diff --git a/src/handlers/next/saleor-webhooks/process-saleor-webhook.test.ts b/src/handlers/platforms/next/saleor-webhooks/process-saleor-webhook.test.ts similarity index 100% rename from src/handlers/next/saleor-webhooks/process-saleor-webhook.test.ts rename to src/handlers/platforms/next/saleor-webhooks/process-saleor-webhook.test.ts diff --git a/src/handlers/next/saleor-webhooks/process-saleor-webhook.ts b/src/handlers/platforms/next/saleor-webhooks/process-saleor-webhook.ts similarity index 92% rename from src/handlers/next/saleor-webhooks/process-saleor-webhook.ts rename to src/handlers/platforms/next/saleor-webhooks/process-saleor-webhook.ts index 237e93df..f347ad2f 100644 --- a/src/handlers/next/saleor-webhooks/process-saleor-webhook.ts +++ b/src/handlers/platforms/next/saleor-webhooks/process-saleor-webhook.ts @@ -2,14 +2,14 @@ import { SpanKind, SpanStatusCode } from "@opentelemetry/api"; import { NextApiRequest } from "next"; import getRawBody from "raw-body"; -import { APL } from "../../../APL"; -import { createDebug } from "../../../debug"; -import { fetchRemoteJwks } from "../../../fetch-remote-jwks"; -import { getBaseUrl, getSaleorHeaders } from "../../../headers"; -import { getOtelTracer } from "../../../open-telemetry"; -import { parseSchemaVersion } from "../../../util"; -import { verifySignatureWithJwks } from "../../../verify-signature"; -import { WebhookContext, WebhookError } from "../../shared/process-saleor-webhook"; +import { APL } from "@/APL"; +import { createDebug } from "@/debug"; +import { fetchRemoteJwks } from "@/fetch-remote-jwks"; +import { WebhookContext, WebhookError } from "@/handlers/shared/process-saleor-webhook"; +import { getBaseUrl, getSaleorHeaders } from "@/headers"; +import { getOtelTracer } from "@/open-telemetry"; +import { parseSchemaVersion } from "@/util"; +import { verifySignatureWithJwks } from "@/verify-signature"; const debug = createDebug("processSaleorWebhook"); diff --git a/src/handlers/next/saleor-webhooks/saleor-async-webhook.test.ts b/src/handlers/platforms/next/saleor-webhooks/saleor-async-webhook.test.ts similarity index 98% rename from src/handlers/next/saleor-webhooks/saleor-async-webhook.test.ts rename to src/handlers/platforms/next/saleor-webhooks/saleor-async-webhook.test.ts index 7c4dbeeb..cf5c716a 100644 --- a/src/handlers/next/saleor-webhooks/saleor-async-webhook.test.ts +++ b/src/handlers/platforms/next/saleor-webhooks/saleor-async-webhook.test.ts @@ -2,8 +2,9 @@ import { ASTNode } from "graphql"; import { createMocks } from "node-mocks-http"; import { afterEach, describe, expect, it, vi } from "vitest"; -import { MockAPL } from "../../../test-utils/mock-apl"; -import { AsyncWebhookEventType } from "../../../types"; +import { MockAPL } from "@/test-utils/mock-apl"; +import { AsyncWebhookEventType } from "@/types"; + import { processSaleorWebhook } from "./process-saleor-webhook"; import { SaleorAsyncWebhook } from "./saleor-async-webhook"; import { NextWebhookApiHandler, WebhookConfig } from "./saleor-webhook"; diff --git a/src/handlers/next/saleor-webhooks/saleor-async-webhook.ts b/src/handlers/platforms/next/saleor-webhooks/saleor-async-webhook.ts similarity index 96% rename from src/handlers/next/saleor-webhooks/saleor-async-webhook.ts rename to src/handlers/platforms/next/saleor-webhooks/saleor-async-webhook.ts index 8efa7a26..327a87ce 100644 --- a/src/handlers/next/saleor-webhooks/saleor-async-webhook.ts +++ b/src/handlers/platforms/next/saleor-webhooks/saleor-async-webhook.ts @@ -1,7 +1,8 @@ import { ASTNode } from "graphql/index"; import { NextApiHandler } from "next"; -import { AsyncWebhookEventType } from "../../../types"; +import { AsyncWebhookEventType } from "@/types"; + import { NextWebhookApiHandler, SaleorWebhook, WebhookConfig } from "./saleor-webhook"; export class SaleorAsyncWebhook extends SaleorWebhook { diff --git a/src/handlers/next/saleor-webhooks/saleor-sync-webhook.test.ts b/src/handlers/platforms/next/saleor-webhooks/saleor-sync-webhook.test.ts similarity index 97% rename from src/handlers/next/saleor-webhooks/saleor-sync-webhook.test.ts rename to src/handlers/platforms/next/saleor-webhooks/saleor-sync-webhook.test.ts index 22431a83..c03c8dd3 100644 --- a/src/handlers/next/saleor-webhooks/saleor-sync-webhook.test.ts +++ b/src/handlers/platforms/next/saleor-webhooks/saleor-sync-webhook.test.ts @@ -1,7 +1,8 @@ import { createMocks } from "node-mocks-http"; import { describe, expect, it, vi } from "vitest"; -import { MockAPL } from "../../../test-utils/mock-apl"; +import { MockAPL } from "@/test-utils/mock-apl"; + import { processSaleorWebhook } from "./process-saleor-webhook"; import { SaleorSyncWebhook } from "./saleor-sync-webhook"; diff --git a/src/handlers/next/saleor-webhooks/saleor-sync-webhook.ts b/src/handlers/platforms/next/saleor-webhooks/saleor-sync-webhook.ts similarity index 86% rename from src/handlers/next/saleor-webhooks/saleor-sync-webhook.ts rename to src/handlers/platforms/next/saleor-webhooks/saleor-sync-webhook.ts index 79f75220..9aaa216b 100644 --- a/src/handlers/next/saleor-webhooks/saleor-sync-webhook.ts +++ b/src/handlers/platforms/next/saleor-webhooks/saleor-sync-webhook.ts @@ -1,7 +1,8 @@ import { NextApiHandler } from "next"; -import { SyncWebhookEventType } from "../../../types"; -import { buildSyncWebhookResponsePayload } from "../../shared/sync-webhook-response-builder"; +import { buildSyncWebhookResponsePayload } from "@/handlers/shared/sync-webhook-response-builder"; +import { SyncWebhookEventType } from "@/types"; + import { NextWebhookApiHandler, SaleorWebhook, WebhookConfig } from "./saleor-webhook"; type InjectedContext = { diff --git a/src/handlers/next/saleor-webhooks/saleor-webhook.ts b/src/handlers/platforms/next/saleor-webhooks/saleor-webhook.ts similarity index 93% rename from src/handlers/next/saleor-webhooks/saleor-webhook.ts rename to src/handlers/platforms/next/saleor-webhooks/saleor-webhook.ts index 3fbf1561..daffe20f 100644 --- a/src/handlers/next/saleor-webhooks/saleor-webhook.ts +++ b/src/handlers/platforms/next/saleor-webhooks/saleor-webhook.ts @@ -1,12 +1,13 @@ import { ASTNode } from "graphql"; import { NextApiHandler, NextApiRequest, NextApiResponse } from "next"; -import { APL } from "../../../APL"; -import { createDebug } from "../../../debug"; -import { gqlAstToString } from "../../../gql-ast-to-string"; -import { AsyncWebhookEventType, SyncWebhookEventType, WebhookManifest } from "../../../types"; -import { WebhookContext, WebhookError } from "../../shared/process-saleor-webhook"; -import { WebhookErrorCodeMap } from "../../shared/saleor-webhook"; +import { APL } from "@/APL"; +import { createDebug } from "@/debug"; +import { gqlAstToString } from "@/gql-ast-to-string"; +import { WebhookContext, WebhookError } from "@/handlers/shared/process-saleor-webhook"; +import { WebhookErrorCodeMap } from "@/handlers/shared/saleor-webhook"; +import { AsyncWebhookEventType, SyncWebhookEventType, WebhookManifest } from "@/types"; + import { processSaleorWebhook } from "./process-saleor-webhook"; const debug = createDebug("SaleorWebhook"); diff --git a/src/handlers/shared/adapter-middleware.ts b/src/handlers/shared/adapter-middleware.ts index ec9d4685..ffea6864 100644 --- a/src/handlers/shared/adapter-middleware.ts +++ b/src/handlers/shared/adapter-middleware.ts @@ -5,8 +5,9 @@ import { SALEOR_EVENT_HEADER, SALEOR_SCHEMA_VERSION, SALEOR_SIGNATURE_HEADER, -} from "../../const"; -import { createMiddlewareDebug } from "../../middleware/middleware-debug"; +} from "@/const"; +import { createMiddlewareDebug } from "@/middleware/middleware-debug"; + import { ActionHandlerResult, HTTPMethod, diff --git a/tsconfig.json b/tsconfig.json index 4863e398..c9ad42cd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,4 +1,5 @@ { + "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { "target": "ES2021", "lib": ["dom", "ES2021"], @@ -9,6 +10,10 @@ "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, - "skipLibCheck": true + "skipLibCheck": true, + "baseUrl": ".", + "paths": { + "@/*": ["src/*"] + } } } diff --git a/tsup.config.ts b/tsup.config.ts index ddd23719..4c815bae 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -13,15 +13,19 @@ export default defineConfig({ "APL/vercel-kv/index": "src/APL/vercel-kv/index.ts", "app-bridge/index": "src/app-bridge/index.ts", "app-bridge/next/index": "src/app-bridge/next/index.ts", - "handlers/next/index": "src/handlers/next/index.ts", - "handlers/fetch-api/index": "src/handlers/fetch-api/index.ts", - "handlers/shared/index": "src/handlers/shared/index.ts", "fetch-middleware/index": "src/fetch-middleware/index.ts", "middleware/index": "src/middleware/index.ts", "settings-manager/index": "src/settings-manager/index.ts", + // Mapped exports + "handlers/next/index": "src/handlers/platforms/next/index.ts", + "handlers/fetch-api/index": "src/handlers/platforms/fetch-api/index.ts", + "handlers/aws-lambda/index": "src/handlers/platforms/fetch-api/index.ts", + "handlers/shared/index": "src/handlers/shared/index.ts", + "handlers/actions/index": "src/handlers/actions/index.ts", + // Virtual export - "handlers/next-app-router/index": "src/handlers/fetch-api/index.ts", + "handlers/next-app-router/index": "src/handlers/platforms/fetch-api/index.ts", }, dts: true, clean: true, From a9c38e5eaf19c108c30a55c40039e9dc5c102437 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 17 Jan 2025 18:36:53 +0100 Subject: [PATCH 40/58] Add baseURL implementation --- .../platforms/aws-lambda/platform-adapter.ts | 23 ++++++++++++++++ .../platforms/fetch-api/platform-adapter.ts | 27 +++++++++++++++++++ .../platforms/next/platform-adapter.ts | 13 +++++++++ .../shared/generic-adapter-use-case-types.ts | 1 + 4 files changed, 64 insertions(+) diff --git a/src/handlers/platforms/aws-lambda/platform-adapter.ts b/src/handlers/platforms/aws-lambda/platform-adapter.ts index 749722ef..6530e38d 100644 --- a/src/handlers/platforms/aws-lambda/platform-adapter.ts +++ b/src/handlers/platforms/aws-lambda/platform-adapter.ts @@ -31,6 +31,29 @@ export class AwsLambdaAdapter implements PlatformAdapterInterface el === "https") || protocols[0]; + + // API Gateway splits deployment into multiple stages which are + // included in the API url (e.g. /dev or /prod) + // More details: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html + const { stage } = this.event.requestContext; + + if (stage) { + return `${protocol}://${host}/${stage}`; + } + + return `${protocol}://${host}`; + } + get method(): HTTPMethod { return this.event.requestContext.http.method as HTTPMethod; } diff --git a/src/handlers/platforms/fetch-api/platform-adapter.ts b/src/handlers/platforms/fetch-api/platform-adapter.ts index b13f7367..2c8a8f13 100644 --- a/src/handlers/platforms/fetch-api/platform-adapter.ts +++ b/src/handlers/platforms/fetch-api/platform-adapter.ts @@ -22,6 +22,33 @@ export class WebApiAdapter implements PlatformAdapterInterface value.trimStart()); + protocol = xForwardedForProtocols.find((el) => el === "https") || xForwardedForProtocols[0]; + } else if (url) { + // Some providers (e.g. Deno Deploy) + // do not set x-forwarded-for header when handling request + // try to get it from URL + protocol = url.protocol.replace(":", ""); + } else { + protocol = "http"; + } + + return `${protocol}://${host}`; + } + get method() { return this.request.method as "POST" | "GET"; } diff --git a/src/handlers/platforms/next/platform-adapter.ts b/src/handlers/platforms/next/platform-adapter.ts index 945712e3..3876c188 100644 --- a/src/handlers/platforms/next/platform-adapter.ts +++ b/src/handlers/platforms/next/platform-adapter.ts @@ -25,6 +25,19 @@ export class NextJsAdapter implements PlatformAdapterInterface el === "https") || protocols[0]; + + return `${protocol}://${host}`; + } + get method() { return this.request.method as "POST" | "GET"; } diff --git a/src/handlers/shared/generic-adapter-use-case-types.ts b/src/handlers/shared/generic-adapter-use-case-types.ts index 92cb6d17..40090f5d 100644 --- a/src/handlers/shared/generic-adapter-use-case-types.ts +++ b/src/handlers/shared/generic-adapter-use-case-types.ts @@ -35,6 +35,7 @@ export interface PlatformAdapterInterface { send(result: ActionHandlerResult): unknown; getHeader(name: string): string | null; getBody(): Promise; + getBaseUrl(): string; method: HTTPMethod; request: T; } From 1677ba85ba7549c5623304c0f15bb93e9be42d47 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 17 Jan 2025 18:40:04 +0100 Subject: [PATCH 41/58] Add manifest action --- .../actions/manifest-action-handler.ts | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 src/handlers/actions/manifest-action-handler.ts diff --git a/src/handlers/actions/manifest-action-handler.ts b/src/handlers/actions/manifest-action-handler.ts new file mode 100644 index 00000000..dda58845 --- /dev/null +++ b/src/handlers/actions/manifest-action-handler.ts @@ -0,0 +1,57 @@ +import { createDebug } from "@/debug"; +import { AppManifest } from "@/types"; + +import { PlatformAdapterMiddleware } from "../shared/adapter-middleware"; +import { + ActionHandlerInterface, + ActionHandlerResult, + PlatformAdapterInterface, +} from "../shared/generic-adapter-use-case-types"; + +const debug = createDebug("create-manifest-handler"); + +export type CreateManifestHandlerOptions = { + manifestFactory(context: { + appBaseUrl: string; + request: T; + /** For Saleor < 3.15 it will be null. */ + schemaVersion: number | null; + }): AppManifest | Promise; +}; + +export class ManifestActionHandler implements ActionHandlerInterface { + constructor(private adapter: PlatformAdapterInterface) {} + + private adapterMiddleware = new PlatformAdapterMiddleware(this.adapter); + + async handleAction(options: CreateManifestHandlerOptions): Promise { + const { schemaVersion } = this.adapterMiddleware.getSaleorHeaders(); + const baseURL = this.adapter.getBaseUrl(); + + debug("Received request with schema version \"%s\" and base URL \"%s\"", schemaVersion, baseURL); + + try { + const manifest = await options.manifestFactory({ + appBaseUrl: baseURL, + request: this.adapter.request, + schemaVersion, + }); + + debug("Executed manifest file"); + + return { + status: 200, + bodyType: "json", + body: manifest, + }; + } catch (e) { + debug("Error while resolving manifest: %O", e); + + return { + status: 500, + bodyType: "string", + body: "Error resolving manifest file.", + }; + } + } +} From 383b0f2e2399c53e5671651817eb3cd18b357a1c Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 17 Jan 2025 18:50:11 +0100 Subject: [PATCH 42/58] Add new register handler implementation --- .../aws-lambda/create-app-register.ts | 4 +- .../aws-lambda/create-manifest-handler.ts | 17 ++++++ .../fetch-api/create-app-register-handler.ts | 2 +- .../fetch-api/create-manifest-handler.ts | 34 +++++------- .../next/create-app-register-handler.ts | 12 ++-- .../platforms/next/create-manifest-handler.ts | 55 +++++-------------- .../platforms/next/platform-adapter.ts | 7 +-- 7 files changed, 54 insertions(+), 77 deletions(-) create mode 100644 src/handlers/platforms/aws-lambda/create-manifest-handler.ts diff --git a/src/handlers/platforms/aws-lambda/create-app-register.ts b/src/handlers/platforms/aws-lambda/create-app-register.ts index 3a7bfc6a..e30b54bf 100644 --- a/src/handlers/platforms/aws-lambda/create-app-register.ts +++ b/src/handlers/platforms/aws-lambda/create-app-register.ts @@ -1,5 +1,3 @@ -import { APIGatewayProxyEventV2, Context } from "aws-lambda"; - import { RegisterActionHandler, RegisterHandlerResponseBody, @@ -38,7 +36,7 @@ export type CreateAppRegisterHandlerOptions = * */ export const createAppRegisterHandler = (config: CreateAppRegisterHandlerOptions): AWSLambdaHandler => - async (event: APIGatewayProxyEventV2, context: Context) => { + async (event, context) => { const adapter = new AwsLambdaAdapter(event, context); const useCase = new RegisterActionHandler(adapter); const result = await useCase.handleAction(config); diff --git a/src/handlers/platforms/aws-lambda/create-manifest-handler.ts b/src/handlers/platforms/aws-lambda/create-manifest-handler.ts new file mode 100644 index 00000000..6435a5fc --- /dev/null +++ b/src/handlers/platforms/aws-lambda/create-manifest-handler.ts @@ -0,0 +1,17 @@ +import { + CreateManifestHandlerOptions as GenericHandlerOptions, + ManifestActionHandler, +} from "@/handlers/actions/manifest-action-handler"; + +import { AwsLambdaAdapter, AWSLambdaHandler, AwsLambdaHandlerInput } from "./platform-adapter"; + +export type CreateManifestHandlerOptions = GenericHandlerOptions; + +export const createManifestHandler = + (config: CreateManifestHandlerOptions): AWSLambdaHandler => + async (event, context) => { + const adapter = new AwsLambdaAdapter(event, context); + const actionHandler = new ManifestActionHandler(adapter); + const result = await actionHandler.handleAction(config); + return adapter.send(result); + }; diff --git a/src/handlers/platforms/fetch-api/create-app-register-handler.ts b/src/handlers/platforms/fetch-api/create-app-register-handler.ts index 3781fd82..abffea2e 100644 --- a/src/handlers/platforms/fetch-api/create-app-register-handler.ts +++ b/src/handlers/platforms/fetch-api/create-app-register-handler.ts @@ -39,7 +39,7 @@ export type CreateAppRegisterHandlerOptions = * */ export const createAppRegisterHandler = (config: CreateAppRegisterHandlerOptions): WebApiHandler => - async (req: Request) => { + async (req) => { const adapter = new WebApiAdapter(req); const useCase = new RegisterActionHandler(adapter); const result = await useCase.handleAction(config); diff --git a/src/handlers/platforms/fetch-api/create-manifest-handler.ts b/src/handlers/platforms/fetch-api/create-manifest-handler.ts index ec514aae..2c463798 100644 --- a/src/handlers/platforms/fetch-api/create-manifest-handler.ts +++ b/src/handlers/platforms/fetch-api/create-manifest-handler.ts @@ -1,25 +1,17 @@ -import { getBaseUrlFetchAPI, getSaleorHeadersFetchAPI } from "@/headers"; -import { AppManifest } from "@/types"; +import { + CreateManifestHandlerOptions as GenericHandlerOptions, + ManifestActionHandler, +} from "@/handlers/actions/manifest-action-handler"; -export type CreateManifestHandlerOptions = { - manifestFactory(context: { - appBaseUrl: string; - request: Request; - /** For Saleor < 3.15 it will be null. */ - schemaVersion: number | null; - }): AppManifest | Promise; -}; +import { WebApiAdapter, WebApiHandler, WebApiHandlerInput } from "./platform-adapter"; -export const createManifestHandler = - (options: CreateManifestHandlerOptions) => async (request: Request) => { - const { schemaVersion } = getSaleorHeadersFetchAPI(request.headers); - const baseURL = getBaseUrlFetchAPI(request); - - const manifest = await options.manifestFactory({ - appBaseUrl: baseURL, - request, - schemaVersion, - }); +export type CreateManifestHandlerOptions = GenericHandlerOptions; - return Response.json(manifest); +export const createManifestHandler = + (config: CreateManifestHandlerOptions): WebApiHandler => + async (request: Request) => { + const adapter = new WebApiAdapter(request); + const actionHandler = new ManifestActionHandler(adapter); + const result = await actionHandler.handleAction(config); + return adapter.send(result); }; diff --git a/src/handlers/platforms/next/create-app-register-handler.ts b/src/handlers/platforms/next/create-app-register-handler.ts index 5b1b27cb..38adfad7 100644 --- a/src/handlers/platforms/next/create-app-register-handler.ts +++ b/src/handlers/platforms/next/create-app-register-handler.ts @@ -1,12 +1,10 @@ -import { NextApiRequest, NextApiResponse } from "next"; - import { RegisterActionHandler, RegisterHandlerResponseBody, } from "@/handlers/actions/register-action-handler"; import { GenericCreateAppRegisterHandlerOptions } from "@/handlers/shared/create-app-register-handler-types"; -import { NextJsAdapter, NextJsHandlerInput } from "./platform-adapter"; +import { NextJsAdapter, NextJsHandler, NextJsHandlerInput } from "./platform-adapter"; // Re-export types for backwards compatibility @@ -37,10 +35,10 @@ export type CreateAppRegisterHandlerOptions = * @see {@link https://docs.saleor.io/developer/extending/apps/architecture/app-requirements#register-url} * */ export const createAppRegisterHandler = - (config: CreateAppRegisterHandlerOptions) => - async (req: NextApiRequest, res: NextApiResponse) => { + (config: CreateAppRegisterHandlerOptions): NextJsHandler => + async (req, res) => { const adapter = new NextJsAdapter(req, res); - const useCase = new RegisterActionHandler(adapter); - const result = await useCase.handleAction(config); + const actionHandler = new RegisterActionHandler(adapter); + const result = await actionHandler.handleAction(config); return adapter.send(result); }; diff --git a/src/handlers/platforms/next/create-manifest-handler.ts b/src/handlers/platforms/next/create-manifest-handler.ts index 5fff0717..67cd4cff 100644 --- a/src/handlers/platforms/next/create-manifest-handler.ts +++ b/src/handlers/platforms/next/create-manifest-handler.ts @@ -1,48 +1,23 @@ -import { NextApiHandler, NextApiRequest } from "next"; +import { + CreateManifestHandlerOptions as GenericCreateManifestHandlerOptions, + ManifestActionHandler, +} from "@/handlers/actions/manifest-action-handler"; -import { createDebug } from "@/debug"; -import { getBaseUrl, getSaleorHeaders } from "@/headers"; -import { AppManifest } from "@/types"; +import { NextJsAdapter, NextJsHandler, NextJsHandlerInput } from "./platform-adapter"; -export type CreateManifestHandlerOptions = { - manifestFactory(context: { - appBaseUrl: string; - request: NextApiRequest; - /** For Saleor < 3.15 it will be null. */ - schemaVersion: number | null; - }): AppManifest | Promise; -}; - -const debug = createDebug("create-manifest-handler"); +export type CreateManifestHandlerOptions = GenericCreateManifestHandlerOptions; /** - * Creates API handler for Next.js. Helps with Manifest creation, hides + * Creates API handler for Next.js page router. + * + * elps with Manifest creation, hides * implementation details if possible - * In the future this will be extracted to separate sdk/next package */ export const createManifestHandler = - (options: CreateManifestHandlerOptions): NextApiHandler => - async (request, response) => { - const { schemaVersion } = getSaleorHeaders(request.headers); - const baseURL = getBaseUrl(request.headers); - - debug("Received request with schema version \"%s\" and base URL \"%s\"", schemaVersion, baseURL); - - try { - const manifest = await options.manifestFactory({ - appBaseUrl: baseURL, - request, - schemaVersion, - }); - - debug("Executed manifest file"); - - return response.status(200).json(manifest); - } catch (e) { - debug("Error while resolving manifest: %O", e); - - return response.status(500).json({ - message: "Error resolving manifest file", - }); - } + (options: CreateManifestHandlerOptions): NextJsHandler => + async (req, res) => { + const adapter = new NextJsAdapter(req, res); + const actionHandler = new ManifestActionHandler(adapter); + const result = await actionHandler.handleAction(options); + return adapter.send(result); }; diff --git a/src/handlers/platforms/next/platform-adapter.ts b/src/handlers/platforms/next/platform-adapter.ts index 3876c188..9d7f8bc1 100644 --- a/src/handlers/platforms/next/platform-adapter.ts +++ b/src/handlers/platforms/next/platform-adapter.ts @@ -6,10 +6,7 @@ import { } from "@/handlers/shared/generic-adapter-use-case-types"; export type NextJsHandlerInput = NextApiRequest; -export type NextJsHandler = ( - req: NextApiRequest, - res: NextApiResponse -) => Promise; +export type NextJsHandler = (req: NextApiRequest, res: NextApiResponse) => Promise; export class NextJsAdapter implements PlatformAdapterInterface { readonly type = "next" as const; @@ -26,7 +23,7 @@ export class NextJsAdapter implements PlatformAdapterInterface Date: Mon, 20 Jan 2025 16:30:18 +0100 Subject: [PATCH 43/58] Fix vitest alias config --- package.json | 1 + pnpm-lock.yaml | 36 +++++++++++++++++++++++++++ vitest.config.ts => vitest.config.mts | 6 ++++- 3 files changed, 42 insertions(+), 1 deletion(-) rename vitest.config.ts => vitest.config.mts (72%) diff --git a/package.json b/package.json index 31f21456..99c76198 100644 --- a/package.json +++ b/package.json @@ -78,6 +78,7 @@ "typescript": "5.4.2", "vi-fetch": "^0.8.0", "vite": "^4.0.4", + "vite-tsconfig-paths": "^5.1.4", "vitest": "^0.28.1" }, "peerDependenciesMeta": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index baa55e2b..c461338a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -150,6 +150,9 @@ importers: vite: specifier: ^4.0.4 version: 4.0.5(@types/node@18.7.15) + vite-tsconfig-paths: + specifier: ^5.1.4 + version: 5.1.4(typescript@5.4.2)(vite@4.0.5(@types/node@18.7.15)) vitest: specifier: ^0.28.1 version: 0.28.1(jsdom@20.0.3) @@ -3271,6 +3274,16 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + tsconfck@3.1.4: + resolution: {integrity: sha512-kdqWFGVJqe+KGYvlSO9NIaWn9jT1Ny4oKVzAJsKii5eoE9snzTJzL4+MMVOMn+fikWGFmKEylcXL710V/kIPJQ==} + engines: {node: ^18 || >=20} + hasBin: true + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + tsconfig-paths@3.14.1: resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==} @@ -3422,6 +3435,14 @@ packages: engines: {node: '>=v14.16.0'} hasBin: true + vite-tsconfig-paths@5.1.4: + resolution: {integrity: sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==} + peerDependencies: + vite: '*' + peerDependenciesMeta: + vite: + optional: true + vite@4.0.5: resolution: {integrity: sha512-7m87RC+caiAxG+8j3jObveRLqaWA/neAdCat6JAZwMkSWqFHOvg8MYe5fAQxVBRAuKAQ1S6XDh3CBQuLNbY33w==} engines: {node: ^14.18.0 || >=16.0.0} @@ -6890,6 +6911,10 @@ snapshots: ts-interface-checker@0.1.13: {} + tsconfck@3.1.4(typescript@5.4.2): + optionalDependencies: + typescript: 5.4.2 + tsconfig-paths@3.14.1: dependencies: '@types/json5': 0.0.29 @@ -7075,6 +7100,17 @@ snapshots: - supports-color - terser + vite-tsconfig-paths@5.1.4(typescript@5.4.2)(vite@4.0.5(@types/node@18.7.15)): + dependencies: + debug: 4.3.4 + globrex: 0.1.2 + tsconfck: 3.1.4(typescript@5.4.2) + optionalDependencies: + vite: 4.0.5(@types/node@18.7.15) + transitivePeerDependencies: + - supports-color + - typescript + vite@4.0.5(@types/node@18.7.15): dependencies: esbuild: 0.16.17 diff --git a/vitest.config.ts b/vitest.config.mts similarity index 72% rename from vitest.config.ts rename to vitest.config.mts index 6b9f320d..8a0e01bc 100644 --- a/vitest.config.ts +++ b/vitest.config.mts @@ -1,10 +1,14 @@ import react from "@vitejs/plugin-react"; +import tsconfigPaths from "vite-tsconfig-paths" import { defineConfig } from "vitest/config"; // https://vitejs.dev/config/ export default defineConfig({ - plugins: [react()], + plugins: [react(), tsconfigPaths()], test: { + alias: { + // "@": "/src", + }, setupFiles: ["./src/setup-tests.ts"], environment: "jsdom", css: false, From b8f0d982776720e955ce0ff85475b12fa03ffb47 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Tue, 21 Jan 2025 13:30:55 +0100 Subject: [PATCH 44/58] Fix failing mocks --- .../next/create-app-register-handler.test.ts | 13 +++++----- .../next/process-protected-handler.test.ts | 13 +++------- .../process-saleor-webhook.test.ts | 26 +++++++++---------- 3 files changed, 22 insertions(+), 30 deletions(-) diff --git a/src/handlers/platforms/next/create-app-register-handler.test.ts b/src/handlers/platforms/next/create-app-register-handler.test.ts index 8d792f09..4cff67d4 100644 --- a/src/handlers/platforms/next/create-app-register-handler.test.ts +++ b/src/handlers/platforms/next/create-app-register-handler.test.ts @@ -2,6 +2,8 @@ import { createMocks } from "node-mocks-http"; import { beforeEach, describe, expect, it, Mock, vi } from "vitest"; import { APL, AuthData } from "@/APL"; +import * as fetchRemoteJwksModule from "@/fetch-remote-jwks"; +import * as getAppIdModule from "@/get-app-id"; import { MockAPL } from "@/test-utils/mock-apl"; import { createAppRegisterHandler } from "./create-app-register-handler"; @@ -9,13 +11,10 @@ import { createAppRegisterHandler } from "./create-app-register-handler"; const mockJwksValue = "{}"; const mockAppId = "42"; -vi.mock("../../get-app-id", () => ({ - getAppId: vi.fn().mockResolvedValue("42"), // can't use var reference, due to hoisting -})); - -vi.mock("../../fetch-remote-jwks", () => ({ - fetchRemoteJwks: vi.fn().mockResolvedValue("{}"), // can't use var reference, due to hoisting -})); +// Cannot use vi.mock on module, due to issues with alias resolution +// in vitest vs TypeScript: https://github.com/vitest-dev/vitest/issues/3105 +vi.spyOn(fetchRemoteJwksModule, "fetchRemoteJwks").mockResolvedValue("{}"); +vi.spyOn(getAppIdModule, "getAppId").mockResolvedValue("42"); describe("create-app-register-handler", () => { let mockApl: APL; diff --git a/src/handlers/platforms/next/process-protected-handler.test.ts b/src/handlers/platforms/next/process-protected-handler.test.ts index ede2966d..fd2ddced 100644 --- a/src/handlers/platforms/next/process-protected-handler.test.ts +++ b/src/handlers/platforms/next/process-protected-handler.test.ts @@ -2,8 +2,10 @@ import { NextApiRequest } from "next/types"; import { createMocks } from "node-mocks-http"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import * as getAppIdModule from "@/get-app-id"; import { getAppId } from "@/get-app-id"; import { MockAPL } from "@/test-utils/mock-apl"; +import * as verifyJWTModule from "@/verify-jwt"; import { verifyJWT } from "@/verify-jwt"; import { processSaleorProtectedHandler } from "./process-protected-handler"; @@ -13,15 +15,8 @@ const validToken = const validAppId = "QXBwOjI3NQ=="; -vi.mock("./@/get-app-id", () => ({ - // eslint-disable-next-line @typescript-eslint/no-unused-vars - getAppId: vi.fn(), -})); - -vi.mock("./@/verify-jwt", () => ({ - // eslint-disable-next-line @typescript-eslint/no-unused-vars - verifyJWT: vi.fn(), -})); +vi.spyOn(getAppIdModule, "getAppId"); +vi.spyOn(verifyJWTModule, "verifyJWT"); describe("processSaleorProtectedHandler", () => { let mockRequest: NextApiRequest; diff --git a/src/handlers/platforms/next/saleor-webhooks/process-saleor-webhook.test.ts b/src/handlers/platforms/next/saleor-webhooks/process-saleor-webhook.test.ts index ef16a5fa..0237a0ec 100644 --- a/src/handlers/platforms/next/saleor-webhooks/process-saleor-webhook.test.ts +++ b/src/handlers/platforms/next/saleor-webhooks/process-saleor-webhook.test.ts @@ -3,32 +3,30 @@ import { createMocks } from "node-mocks-http"; import rawBody from "raw-body"; import { beforeEach, describe, expect, it, vi } from "vitest"; -import { MockAPL } from "../../../test-utils/mock-apl"; +import { MockAPL } from "@/test-utils/mock-apl"; +import * as verifySignatureModule from "@/verify-signature"; + import { processSaleorWebhook } from "./process-saleor-webhook"; -vi.mock("../../../verify-signature", () => ({ - // eslint-disable-next-line @typescript-eslint/no-unused-vars - verifySignature: vi.fn((domain, signature) => { - if (signature !== "mocked_signature") { - throw new Error("Wrong signature"); - } - }), - verifySignatureFromApiUrl: vi.fn((domain, signature) => { +vi.spyOn(verifySignatureModule, "verifySignatureFromApiUrl").mockImplementation( + async (domain, signature) => { if (signature !== "mocked_signature") { throw new Error("Wrong signature"); } - }), - // eslint-disable-next-line @typescript-eslint/no-unused-vars - verifySignatureWithJwks: vi.fn((jwks, signature, body) => { + } +); +vi.spyOn(verifySignatureModule, "verifySignatureWithJwks").mockImplementation( + async (domain, signature) => { if (signature !== "mocked_signature") { throw new Error("Wrong signature"); } - }), -})); + } +); vi.mock("raw-body", () => ({ default: vi.fn().mockResolvedValue("{}"), })); + describe("processAsyncSaleorWebhook", () => { let mockRequest: NextApiRequest; From ab1c2691396108b99632a7d426449f85d2bf9db8 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Tue, 21 Jan 2025 13:32:18 +0100 Subject: [PATCH 45/58] Fix TS errors --- .../platforms/next/process-protected-handler.ts | 11 +---------- src/handlers/shared/protected-handler.ts | 10 +++++++++- src/handlers/shared/validate-allow-saleor-urls.ts | 2 +- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/handlers/platforms/next/process-protected-handler.ts b/src/handlers/platforms/next/process-protected-handler.ts index ff55be09..998756a4 100644 --- a/src/handlers/platforms/next/process-protected-handler.ts +++ b/src/handlers/platforms/next/process-protected-handler.ts @@ -3,6 +3,7 @@ import { NextApiRequest } from "next"; import { APL } from "@/APL"; import { createDebug } from "@/debug"; +import { SaleorProtectedHandlerError } from "@/handlers/shared/protected-handler"; import { ProtectedHandlerContext } from "@/handlers/shared/protected-handler-context"; import { getBaseUrl, getSaleorHeaders } from "@/headers"; import { getOtelTracer } from "@/open-telemetry"; @@ -12,16 +13,6 @@ import { verifyJWT } from "@/verify-jwt"; const debug = createDebug("processProtectedHandler"); -export type SaleorProtectedHandlerError = - | "OTHER" - | "MISSING_HOST_HEADER" - | "MISSING_DOMAIN_HEADER" - | "MISSING_API_URL_HEADER" - | "MISSING_AUTHORIZATION_BEARER_HEADER" - | "NOT_REGISTERED" - | "JWT_VERIFICATION_FAILED" - | "NO_APP_ID"; - export class ProtectedHandlerError extends Error { errorType: SaleorProtectedHandlerError = "OTHER"; diff --git a/src/handlers/shared/protected-handler.ts b/src/handlers/shared/protected-handler.ts index bcf64907..fc9ef166 100644 --- a/src/handlers/shared/protected-handler.ts +++ b/src/handlers/shared/protected-handler.ts @@ -1,4 +1,12 @@ -import { SaleorProtectedHandlerError } from "../next"; +export type SaleorProtectedHandlerError = + | "OTHER" + | "MISSING_HOST_HEADER" + | "MISSING_DOMAIN_HEADER" + | "MISSING_API_URL_HEADER" + | "MISSING_AUTHORIZATION_BEARER_HEADER" + | "NOT_REGISTERED" + | "JWT_VERIFICATION_FAILED" + | "NO_APP_ID"; export const ProtectedHandlerErrorCodeMap: Record = { OTHER: 500, diff --git a/src/handlers/shared/validate-allow-saleor-urls.ts b/src/handlers/shared/validate-allow-saleor-urls.ts index 03875027..58a91fc4 100644 --- a/src/handlers/shared/validate-allow-saleor-urls.ts +++ b/src/handlers/shared/validate-allow-saleor-urls.ts @@ -1,4 +1,4 @@ -import { CreateAppRegisterHandlerOptions } from "../next/create-app-register-handler"; +import { CreateAppRegisterHandlerOptions } from "../platforms/next/create-app-register-handler"; export const validateAllowSaleorUrls = ( saleorApiUrl: string, From 91562da53b8c6266e58701b7378a58e93e3b3b78 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Tue, 21 Jan 2025 15:49:20 +0100 Subject: [PATCH 46/58] Refactor protected handler validation --- .../aws-lambda/create-protected-handler.ts | 49 +++++ src/handlers/platforms/aws-lambda/index.ts | 4 + .../fetch-api/create-protected-handler.ts | 46 ++-- src/handlers/platforms/fetch-api/index.ts | 2 +- .../fetch-api/process-protected-handler.ts | 163 -------------- .../next/create-protected-handler.ts | 45 ++-- src/handlers/platforms/next/index.ts | 2 +- .../next/process-protected-handler.ts | 4 +- src/handlers/shared/index.ts | 5 +- .../shared/protected-action-validator.ts | 198 ++++++++++++++++++ .../shared/protected-handler-context.ts | 8 - 11 files changed, 302 insertions(+), 224 deletions(-) create mode 100644 src/handlers/platforms/aws-lambda/create-protected-handler.ts create mode 100644 src/handlers/platforms/aws-lambda/index.ts delete mode 100644 src/handlers/platforms/fetch-api/process-protected-handler.ts create mode 100644 src/handlers/shared/protected-action-validator.ts delete mode 100644 src/handlers/shared/protected-handler-context.ts diff --git a/src/handlers/platforms/aws-lambda/create-protected-handler.ts b/src/handlers/platforms/aws-lambda/create-protected-handler.ts new file mode 100644 index 00000000..2de47291 --- /dev/null +++ b/src/handlers/platforms/aws-lambda/create-protected-handler.ts @@ -0,0 +1,49 @@ +import { APIGatewayProxyEventV2, APIGatewayProxyResultV2, Context } from "aws-lambda"; + +import { APL } from "@/APL"; +import { + ProtectedActionValidator, + ProtectedHandlerContext, +} from "@/handlers/shared/protected-action-validator"; +import { Permission } from "@/types"; + +import { AwsLambdaAdapter, AWSLambdaHandler } from "./platform-adapter"; + +export type AwsLambdaProtectedHandler = ( + event: APIGatewayProxyEventV2, + context: Context, + saleorContext: ProtectedHandlerContext +) => Promise; + +/** + * Wraps provided function, to ensure incoming request comes from Saleor Dashboard. + * Also provides additional `saleorContext` object containing request properties. + */ +export const createProtectedHandler = + ( + handlerFn: AwsLambdaProtectedHandler, + apl: APL, + requiredPermissions?: Permission[] + ): AWSLambdaHandler => + async (event, context) => { + const adapter = new AwsLambdaAdapter(event, context); + const actionValidator = new ProtectedActionValidator(adapter); + const validationResult = await actionValidator.validateRequest({ + apl, + requiredPermissions, + }); + + if (validationResult.result === "failure") { + return adapter.send(validationResult.value); + } + + const saleorContext = validationResult.value; + try { + return await handlerFn(event, context, saleorContext); + } catch (err) { + return { + statusCode: 500, + body: "Unexpected Server Error", + }; + } + }; diff --git a/src/handlers/platforms/aws-lambda/index.ts b/src/handlers/platforms/aws-lambda/index.ts new file mode 100644 index 00000000..ba7cba5f --- /dev/null +++ b/src/handlers/platforms/aws-lambda/index.ts @@ -0,0 +1,4 @@ +export * from "./create-app-register"; +export * from "./create-manifest-handler"; +export * from "./create-protected-handler"; +export * from "./platform-adapter"; diff --git a/src/handlers/platforms/fetch-api/create-protected-handler.ts b/src/handlers/platforms/fetch-api/create-protected-handler.ts index 4b17afb3..052b99f5 100644 --- a/src/handlers/platforms/fetch-api/create-protected-handler.ts +++ b/src/handlers/platforms/fetch-api/create-protected-handler.ts @@ -1,12 +1,11 @@ import { APL } from "@/APL"; -import { createDebug } from "@/debug"; -import { ProtectedHandlerErrorCodeMap } from "@/handlers/shared/protected-handler"; -import { ProtectedHandlerContext } from "@/handlers/shared/protected-handler-context"; +import { + ProtectedActionValidator, + ProtectedHandlerContext, +} from "@/handlers/shared/protected-action-validator"; import { Permission } from "@/types"; -import { processSaleorProtectedHandler, ProtectedHandlerError } from "./process-protected-handler"; - -const debug = createDebug("WebAPI:ProtectedHandler"); +import { WebApiAdapter } from "./platform-adapter"; export type WebApiProtectedHandler = ( request: Request, @@ -19,23 +18,22 @@ export const createProtectedHandler = apl: APL, requiredPermissions?: Permission[] ): WebApiProtectedHandler => - (request) => { - debug("Protected handler called"); - return processSaleorProtectedHandler({ request, apl, requiredPermissions }) - .then(async (ctx) => { - debug("Incoming request validated. Call handlerFn"); - return handlerFn(request, ctx); - }) - .catch((e) => { - debug("Unexpected error during processing the request"); + async (request) => { + const adapter = new WebApiAdapter(request); + const actionValidator = new ProtectedActionValidator(adapter); + const validationResult = await actionValidator.validateRequest({ + apl, + requiredPermissions, + }); + + if (validationResult.result === "failure") { + return adapter.send(validationResult.value); + } - if (e instanceof ProtectedHandlerError) { - debug(`Validation error: ${e.message}`); - return new Response("Invalid request", { - status: ProtectedHandlerErrorCodeMap[e.errorType] || 400, - }); - } - debug("Unexpected error: %O", e); - return new Response("Unexpected error while handling request", { status: 500 }); - }); + const context = validationResult.value; + try { + return await handlerFn(request, context); + } catch (err) { + return new Response("Unexpected server error", { status: 500 }); + } }; diff --git a/src/handlers/platforms/fetch-api/index.ts b/src/handlers/platforms/fetch-api/index.ts index 3bc2ff5a..b1ad0cd4 100644 --- a/src/handlers/platforms/fetch-api/index.ts +++ b/src/handlers/platforms/fetch-api/index.ts @@ -1,6 +1,6 @@ export * from "./create-app-register-handler"; export * from "./create-manifest-handler"; export * from "./create-protected-handler"; -export * from "./process-protected-handler"; +export * from "./platform-adapter"; export * from "./saleor-webhooks/saleor-async-webhook"; export * from "./saleor-webhooks/saleor-sync-webhook"; diff --git a/src/handlers/platforms/fetch-api/process-protected-handler.ts b/src/handlers/platforms/fetch-api/process-protected-handler.ts deleted file mode 100644 index 0f2dd4cb..00000000 --- a/src/handlers/platforms/fetch-api/process-protected-handler.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { SpanKind, SpanStatusCode } from "@opentelemetry/api"; - -import { APL } from "@/APL"; -import { createDebug } from "@/debug"; -import { ProtectedHandlerContext } from "@/handlers/shared/protected-handler-context"; -import { getBaseUrlFetchAPI, getSaleorHeadersFetchAPI } from "@/headers"; -import { getOtelTracer } from "@/open-telemetry"; -import { Permission } from "@/types"; -import { extractUserFromJwt } from "@/util/extract-user-from-jwt"; -import { verifyJWT } from "@/verify-jwt"; - -const debug = createDebug("WebAPI:processProtectedHandler"); - -export type SaleorProtectedHandlerError = - | "OTHER" - | "MISSING_HOST_HEADER" - | "MISSING_DOMAIN_HEADER" - | "MISSING_API_URL_HEADER" - | "MISSING_AUTHORIZATION_BEARER_HEADER" - | "NOT_REGISTERED" - | "JWT_VERIFICATION_FAILED" - | "NO_APP_ID"; - -export class ProtectedHandlerError extends Error { - errorType: SaleorProtectedHandlerError = "OTHER"; - - constructor(message: string, errorType: SaleorProtectedHandlerError) { - super(message); - if (errorType) { - this.errorType = errorType; - } - Object.setPrototypeOf(this, ProtectedHandlerError.prototype); - } -} - -interface ProcessSaleorProtectedHandlerArgs { - request: Request; - apl: APL; - requiredPermissions?: Permission[]; -} - -type ProcessAsyncSaleorProtectedHandler = ( - props: ProcessSaleorProtectedHandlerArgs -) => Promise; - -/** - * Perform security checks on given request and return ProtectedHandlerContext object. - * In case of validation issues, instance of the ProtectedHandlerError will be thrown. - * - * Can pass entire next request or Headers with saleorApiUrl and token - */ -export const processSaleorProtectedHandler: ProcessAsyncSaleorProtectedHandler = async ({ - request, - apl, - requiredPermissions, -}: ProcessSaleorProtectedHandlerArgs): Promise => { - const tracer = getOtelTracer(); - - return tracer.startActiveSpan( - "processSaleorProtectedHandler", - { - kind: SpanKind.INTERNAL, - attributes: { - requiredPermissions, - }, - }, - async (span) => { - debug("Request processing started"); - - const { saleorApiUrl, authorizationBearer: token } = getSaleorHeadersFetchAPI( - request.headers - ); - - const baseUrl = getBaseUrlFetchAPI(request); - - span.setAttribute("saleorApiUrl", saleorApiUrl ?? ""); - - if (!baseUrl) { - span - .setStatus({ - code: SpanStatusCode.ERROR, - message: "Missing host header", - }) - .end(); - - debug("Missing host header"); - - throw new ProtectedHandlerError("Missing host header", "MISSING_HOST_HEADER"); - } - - if (!saleorApiUrl) { - span - .setStatus({ - code: SpanStatusCode.ERROR, - message: "Missing saleor-api-url header", - }) - .end(); - - debug("Missing saleor-api-url header"); - - throw new ProtectedHandlerError("Missing saleor-api-url header", "MISSING_API_URL_HEADER"); - } - - if (!token) { - span - .setStatus({ - code: SpanStatusCode.ERROR, - message: "Missing authorization-bearer header", - }) - .end(); - - debug("Missing authorization-bearer header"); - - throw new ProtectedHandlerError( - "Missing authorization-bearer header", - "MISSING_AUTHORIZATION_BEARER_HEADER" - ); - } - - // Check if API URL has been registered in the APL - const authData = await apl.get(saleorApiUrl); - - if (!authData) { - span - .setStatus({ - code: SpanStatusCode.ERROR, - message: "APL didn't found auth data for API URL", - }) - .end(); - - debug("APL didn't found auth data for API URL %s", saleorApiUrl); - - throw new ProtectedHandlerError( - `Can't find auth data for saleorApiUrl ${saleorApiUrl}. Please register the application`, - "NOT_REGISTERED" - ); - } - - try { - await verifyJWT({ appId: authData.appId, token, saleorApiUrl, requiredPermissions }); - } catch (e) { - span - .setStatus({ - code: SpanStatusCode.ERROR, - message: "JWT verification failed", - }) - .end(); - - throw new ProtectedHandlerError("JWT verification failed: ", "JWT_VERIFICATION_FAILED"); - } - - const userJwtPayload = extractUserFromJwt(token); - - span.end(); - - return { - baseUrl, - authData, - user: userJwtPayload, - }; - } - ); -}; diff --git a/src/handlers/platforms/next/create-protected-handler.ts b/src/handlers/platforms/next/create-protected-handler.ts index 9bc76b92..efeccaa3 100644 --- a/src/handlers/platforms/next/create-protected-handler.ts +++ b/src/handlers/platforms/next/create-protected-handler.ts @@ -1,14 +1,13 @@ import { NextApiHandler, NextApiRequest, NextApiResponse } from "next"; import { APL } from "@/APL"; -import { createDebug } from "@/debug"; -import { ProtectedHandlerErrorCodeMap } from "@/handlers/shared/protected-handler"; -import { ProtectedHandlerContext } from "@/handlers/shared/protected-handler-context"; +import { + ProtectedActionValidator, + ProtectedHandlerContext, +} from "@/handlers/shared/protected-action-validator"; import { Permission } from "@/types"; -import { processSaleorProtectedHandler, ProtectedHandlerError } from "./process-protected-handler"; - -const debug = createDebug("ProtectedHandler"); +import { NextJsAdapter } from "./platform-adapter"; export type NextProtectedApiHandler = ( req: NextApiRequest, @@ -26,26 +25,22 @@ export const createProtectedHandler = apl: APL, requiredPermissions?: Permission[] ): NextApiHandler => - (req, res) => { - debug("Protected handler called"); - processSaleorProtectedHandler({ - req, + async (req, res) => { + const adapter = new NextJsAdapter(req, res); + const actionValidator = new ProtectedActionValidator(adapter); + const validationResult = await actionValidator.validateRequest({ apl, requiredPermissions, - }) - .then(async (context) => { - debug("Incoming request validated. Call handlerFn"); - return handlerFn(req, res, context); - }) - .catch((e) => { - debug("Unexpected error during processing the request"); + }); + + if (validationResult.result === "failure") { + return adapter.send(validationResult.value); + } - if (e instanceof ProtectedHandlerError) { - debug(`Validation error: ${e.message}`); - res.status(ProtectedHandlerErrorCodeMap[e.errorType] || 400).end(); - return; - } - debug("Unexpected error: %O", e); - res.status(500).end(); - }); + const context = validationResult.value; + try { + return handlerFn(req, res, context); + } catch (err) { + return res.status(500).end(); + } }; diff --git a/src/handlers/platforms/next/index.ts b/src/handlers/platforms/next/index.ts index 3bf56a88..06198c61 100644 --- a/src/handlers/platforms/next/index.ts +++ b/src/handlers/platforms/next/index.ts @@ -1,5 +1,5 @@ // Re-export to avoid breaking changes -export * from "../../shared/protected-handler-context"; +export * from "../../shared/protected-action-validator"; export * from "../../shared/sync-webhook-response-builder"; export * from "./create-app-register-handler"; export * from "./create-manifest-handler"; diff --git a/src/handlers/platforms/next/process-protected-handler.ts b/src/handlers/platforms/next/process-protected-handler.ts index 998756a4..9476e1ab 100644 --- a/src/handlers/platforms/next/process-protected-handler.ts +++ b/src/handlers/platforms/next/process-protected-handler.ts @@ -3,8 +3,8 @@ import { NextApiRequest } from "next"; import { APL } from "@/APL"; import { createDebug } from "@/debug"; +import { ProtectedHandlerContext } from "@/handlers/shared/protected-action-validator"; import { SaleorProtectedHandlerError } from "@/handlers/shared/protected-handler"; -import { ProtectedHandlerContext } from "@/handlers/shared/protected-handler-context"; import { getBaseUrl, getSaleorHeaders } from "@/headers"; import { getOtelTracer } from "@/open-telemetry"; import { Permission } from "@/types"; @@ -40,6 +40,8 @@ type ProcessAsyncSaleorProtectedHandler = ( * In case of validation issues, instance of the ProtectedHandlerError will be thrown. * * Can pass entire next request or Headers with saleorApiUrl and token + * + * @deprecated Use ProtectedActionValidator class */ export const processSaleorProtectedHandler: ProcessAsyncSaleorProtectedHandler = async ({ req, diff --git a/src/handlers/shared/index.ts b/src/handlers/shared/index.ts index abb51a05..2e928dfd 100644 --- a/src/handlers/shared/index.ts +++ b/src/handlers/shared/index.ts @@ -1 +1,4 @@ -export * from "./protected-handler-context"; +export * from "./adapter-middleware"; +export * from "./create-app-register-handler-types"; +export * from "./generic-adapter-use-case-types"; +export * from "./protected-action-validator"; diff --git a/src/handlers/shared/protected-action-validator.ts b/src/handlers/shared/protected-action-validator.ts new file mode 100644 index 00000000..994f234f --- /dev/null +++ b/src/handlers/shared/protected-action-validator.ts @@ -0,0 +1,198 @@ +import { SpanKind, SpanStatusCode } from "@opentelemetry/api"; + +import { APL, AuthData } from "@/APL"; +import { createDebug } from "@/debug"; +import { getOtelTracer } from "@/open-telemetry"; +import { Permission } from "@/types"; +import { extractUserFromJwt, TokenUserPayload } from "@/util/extract-user-from-jwt"; +import { verifyJWT } from "@/verify-jwt"; + +import { PlatformAdapterMiddleware } from "./adapter-middleware"; +import { ActionHandlerResult, PlatformAdapterInterface } from "./generic-adapter-use-case-types"; + +export type ProtectedHandlerConfig = { + apl: APL; + requiredPermissions?: Permission[]; +}; + +export type ProtectedHandlerContext = { + baseUrl: string; + authData: AuthData; + user: TokenUserPayload; +}; + +export type ValidationResult = + | { result: "failure"; value: ActionHandlerResult } + | { result: "ok"; value: ProtectedHandlerContext }; + +export class ProtectedActionValidator { + // Name left for backwards compatibility + private debug = createDebug("processProtectedHandler"); + + private tracer = getOtelTracer(); + + constructor(private adapter: PlatformAdapterInterface) {} + + private adapterMiddleware = new PlatformAdapterMiddleware(this.adapter); + + /** Validates received request if it's legitimate webhook request from Saleor + * returns ActionHandlerResult if request is invalid and must be terminated early + * */ + async validateRequest(config: ProtectedHandlerConfig): Promise { + return this.tracer.startActiveSpan( + "processSaleorProtectedHandler", + { + kind: SpanKind.INTERNAL, + attributes: { + requiredPermissions: config.requiredPermissions, + }, + }, + async (span): Promise => { + this.debug("Request processing started"); + + const { saleorApiUrl, authorizationBearer: token } = + this.adapterMiddleware.getSaleorHeaders(); + + const baseUrl = this.adapter.getBaseUrl(); + + span.setAttribute("saleorApiUrl", saleorApiUrl ?? ""); + + if (!baseUrl) { + span + .setStatus({ + code: SpanStatusCode.ERROR, + message: "Missing host header", + }) + .end(); + + this.debug("Missing host header"); + + return { + result: "failure", + value: { + bodyType: "string", + status: 400, + body: "Validation error: Missing host header", + }, + }; + } + + if (!saleorApiUrl) { + span + .setStatus({ + code: SpanStatusCode.ERROR, + message: "Missing saleor-api-url header", + }) + .end(); + + this.debug("Missing saleor-api-url header"); + + return { + result: "failure", + value: { + bodyType: "string", + status: 400, + body: "Validation error: Missing saleor-api-url header", + }, + }; + } + + if (!token) { + span + .setStatus({ + code: SpanStatusCode.ERROR, + message: "Missing authorization-bearer header", + }) + .end(); + + this.debug("Missing authorization-bearer header"); + + return { + result: "failure", + value: { + bodyType: "string", + status: 400, + body: "Validation error: Missing authorization-bearer header", + }, + }; + } + + // Check if API URL has been registered in the APL + const authData = await config.apl.get(saleorApiUrl); + + if (!authData) { + span + .setStatus({ + code: SpanStatusCode.ERROR, + message: "APL didn't found auth data for API URL", + }) + .end(); + + this.debug("APL didn't found auth data for API URL %s", saleorApiUrl); + + return { + result: "failure", + value: { + bodyType: "string", + status: 401, + body: `Validation error: Can't find auth data for saleorApiUrl ${saleorApiUrl}. Please register the application`, + }, + }; + } + + try { + await verifyJWT({ + appId: authData.appId, + token, + saleorApiUrl, + requiredPermissions: config.requiredPermissions, + }); + } catch (e) { + span + .setStatus({ + code: SpanStatusCode.ERROR, + message: "JWT verification failed", + }) + .end(); + + return { + result: "failure", + value: { + bodyType: "string", + status: 401, + body: "Validation error: JWT verification failed", + }, + }; + } + + try { + const userJwtPayload = extractUserFromJwt(token); + + span.end(); + return { + result: "ok", + value: { + baseUrl, + authData, + user: userJwtPayload, + }, + }; + } catch (err) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: "Error parsing user from JWT", + }); + span.end(); + return { + result: "failure", + value: { + bodyType: "string", + status: 500, + body: "Unexpected error: parsing user from JWT", + }, + }; + } + } + ); + } +} diff --git a/src/handlers/shared/protected-handler-context.ts b/src/handlers/shared/protected-handler-context.ts deleted file mode 100644 index 71bb42d3..00000000 --- a/src/handlers/shared/protected-handler-context.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { AuthData } from "../../APL"; -import { TokenUserPayload } from "../../util/extract-user-from-jwt"; - -export type ProtectedHandlerContext = { - baseUrl: string; - authData: AuthData; - user: TokenUserPayload; -}; From d52f28b17f02ffd105c354421e208a158e638899 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Thu, 23 Jan 2025 14:57:34 +0100 Subject: [PATCH 47/58] Add getRawBody handler --- src/handlers/platforms/aws-lambda/platform-adapter.ts | 9 +++++++++ src/handlers/platforms/fetch-api/platform-adapter.ts | 5 +++++ src/handlers/platforms/next/platform-adapter.ts | 9 +++++++++ src/handlers/shared/generic-adapter-use-case-types.ts | 1 + 4 files changed, 24 insertions(+) diff --git a/src/handlers/platforms/aws-lambda/platform-adapter.ts b/src/handlers/platforms/aws-lambda/platform-adapter.ts index 6530e38d..4a58f376 100644 --- a/src/handlers/platforms/aws-lambda/platform-adapter.ts +++ b/src/handlers/platforms/aws-lambda/platform-adapter.ts @@ -31,6 +31,15 @@ export class AwsLambdaAdapter implements PlatformAdapterInterface { + const { body } = this.request; + if (!body) { + return null; + } + + return body; + } + getBaseUrl(): string { const xForwardedProto = this.getHeader("X-Forwarded-Proto") || "https"; const host = this.getHeader("Host"); diff --git a/src/handlers/platforms/fetch-api/platform-adapter.ts b/src/handlers/platforms/fetch-api/platform-adapter.ts index 2c8a8f13..94c22325 100644 --- a/src/handlers/platforms/fetch-api/platform-adapter.ts +++ b/src/handlers/platforms/fetch-api/platform-adapter.ts @@ -22,6 +22,11 @@ export class WebApiAdapter implements PlatformAdapterInterface { + return ( + await getRawBody(this.request, { + length: this.request.headers["content-length"], + }) + ).toString(); + } + getBaseUrl(): string { const { host, "x-forwarded-proto": xForwardedProto = "http" } = this.request.headers; diff --git a/src/handlers/shared/generic-adapter-use-case-types.ts b/src/handlers/shared/generic-adapter-use-case-types.ts index 40090f5d..e2a4d378 100644 --- a/src/handlers/shared/generic-adapter-use-case-types.ts +++ b/src/handlers/shared/generic-adapter-use-case-types.ts @@ -35,6 +35,7 @@ export interface PlatformAdapterInterface { send(result: ActionHandlerResult): unknown; getHeader(name: string): string | null; getBody(): Promise; + getRawBody(): Promise; getBaseUrl(): string; method: HTTPMethod; request: T; From 36d9088e145cf271be555ec681454f5b7acf4d7c Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Thu, 23 Jan 2025 16:00:32 +0100 Subject: [PATCH 48/58] Rewrite webhook validation to use adapter --- .../next/saleor-webhooks/saleor-webhook.ts | 85 ++--- .../shared/saleor-webhook-validator.ts | 201 ++++++++++++ src/handlers/shared/saleor-webhook.ts | 3 +- src/handlers/webhooks/abstract-webhook.ts | 301 ++++++++++++++++++ 4 files changed, 548 insertions(+), 42 deletions(-) create mode 100644 src/handlers/shared/saleor-webhook-validator.ts create mode 100644 src/handlers/webhooks/abstract-webhook.ts diff --git a/src/handlers/platforms/next/saleor-webhooks/saleor-webhook.ts b/src/handlers/platforms/next/saleor-webhooks/saleor-webhook.ts index daffe20f..a56a8876 100644 --- a/src/handlers/platforms/next/saleor-webhooks/saleor-webhook.ts +++ b/src/handlers/platforms/next/saleor-webhooks/saleor-webhook.ts @@ -6,9 +6,10 @@ import { createDebug } from "@/debug"; import { gqlAstToString } from "@/gql-ast-to-string"; import { WebhookContext, WebhookError } from "@/handlers/shared/process-saleor-webhook"; import { WebhookErrorCodeMap } from "@/handlers/shared/saleor-webhook"; +import { SaleorWebhookValidator } from "@/handlers/shared/saleor-webhook-validator"; import { AsyncWebhookEventType, SyncWebhookEventType, WebhookManifest } from "@/types"; -import { processSaleorWebhook } from "./process-saleor-webhook"; +import { NextJsAdapter } from "../platform-adapter"; const debug = createDebug("SaleorWebhook"); @@ -131,60 +132,62 @@ export abstract class SaleorWebhook< */ createHandler(handlerFn: NextWebhookApiHandler): NextApiHandler { return async (req, res) => { + const adapter = new NextJsAdapter(req, res); + const webhookValidator = new SaleorWebhookValidator(adapter); + debug(`Handler for webhook ${this.name} called`); + const validationResult = await webhookValidator.validateRequest({ allowedEvent: this.event, apl: this.apl }); - await processSaleorWebhook({ - req, - apl: this.apl, - allowedEvent: this.event, - }) - .then(async (context) => { - debug("Incoming request validated. Call handlerFn"); + if (validationResult.result === "ok") { + debug("Incoming request validated. Call handlerFn"); - return handlerFn(req, res, { ...(this.extraContext ?? ({} as TExtras)), ...context }); - }) - .catch(async (e) => { - debug(`Unexpected error during processing the webhook ${this.name}`); + return handlerFn(req, res, { ...(this.extraContext ?? ({} as TExtras)), ...validationResult.context }); + } - if (e instanceof WebhookError) { - debug(`Validation error: ${e.message}`); + debug(`Unexpected error during processing the webhook ${this.name}`); + const e = validationResult.error; - if (this.onError) { - this.onError(e, req, res); - } + if (e instanceof WebhookError) { + debug(`Validation error: ${e.message}`); - if (this.formatErrorResponse) { - const { code, body } = await this.formatErrorResponse(e, req, res); + if (this.onError) { + this.onError(e, req, res); + } - res.status(code).send(body); + if (this.formatErrorResponse) { + const { code, body } = await this.formatErrorResponse(e, req, res); - return; - } + res.status(code).send(body); - res.status(WebhookErrorCodeMap[e.errorType] || 400).send({ - error: { - type: e.errorType, - message: e.message, - }, - }); - return; - } - debug("Unexpected error: %O", e); + return; + } - if (this.onError) { - this.onError(e, req, res); - } + res.status(WebhookErrorCodeMap[e.errorType] || 400).send({ + error: { + type: e.errorType, + message: e.message, + }, + }); + return; + } + debug("Unexpected error: %O", e); - if (this.formatErrorResponse) { - const { code, body } = await this.formatErrorResponse(e, req, res); + if (this.onError) { + this.onError(e, req, res); + } + + if (this.formatErrorResponse) { + const { code, body } = await this.formatErrorResponse(e, req, res); + + res.status(code).send(body); + + return; + } + + res.status(500).end(); - res.status(code).send(body); - return; - } - res.status(500).end(); - }); }; } } diff --git a/src/handlers/shared/saleor-webhook-validator.ts b/src/handlers/shared/saleor-webhook-validator.ts new file mode 100644 index 00000000..b71af2b3 --- /dev/null +++ b/src/handlers/shared/saleor-webhook-validator.ts @@ -0,0 +1,201 @@ +import { SpanKind, SpanStatusCode } from "@opentelemetry/api"; + +import { APL } from "@/APL"; +import { createDebug, } from "@/debug"; +import { fetchRemoteJwks } from "@/fetch-remote-jwks"; +import { getOtelTracer } from "@/open-telemetry"; +import { parseSchemaVersion } from "@/util"; +import { verifySignatureWithJwks } from "@/verify-signature"; + +import { PlatformAdapterMiddleware } from "./adapter-middleware"; +import { PlatformAdapterInterface } from "./generic-adapter-use-case-types"; +import { WebhookContext, WebhookError } from "./process-saleor-webhook"; + +type WebhookValidationResult = { result: "ok", context: WebhookContext } | { result: "failure", error: WebhookError }; + +export class SaleorWebhookValidator { + private debug = createDebug("processProtectedHandler"); + + private tracer = getOtelTracer(); + + constructor(private adapter: PlatformAdapterInterface) { } + + private adapterMiddleware = new PlatformAdapterMiddleware(this.adapter); + + async validateRequest({ allowedEvent, apl }: { allowedEvent: string, apl: APL }): Promise> { + try { + const context = await this.validateRequestOrThrowError({ allowedEvent, apl }); + + return { + result: "ok", + context, + }; + } catch (err) { + return { + result: "failure", + error: err as WebhookError, + }; + } + } + + private async validateRequestOrThrowError({ allowedEvent, apl }: { allowedEvent: string, apl: APL }): Promise> { + return this.tracer.startActiveSpan( + "processSaleorWebhook", + { + kind: SpanKind.INTERNAL, + attributes: { + allowedEvent, + }, + }, + async (span) => { + try { + this.debug("Request processing started"); + + if (this.adapter.method !== "POST") { + this.debug("Wrong HTTP method"); + throw new WebhookError("Wrong request method, only POST allowed", "WRONG_METHOD"); + } + + const { event, signature, saleorApiUrl } = this.adapterMiddleware.getSaleorHeaders(); + const baseUrl = this.adapter.getBaseUrl(); + + if (!baseUrl) { + this.debug("Missing host header"); + throw new WebhookError("Missing host header", "MISSING_HOST_HEADER"); + } + + if (!saleorApiUrl) { + this.debug("Missing saleor-api-url header"); + throw new WebhookError("Missing saleor-api-url header", "MISSING_API_URL_HEADER"); + } + + if (!event) { + this.debug("Missing saleor-event header"); + throw new WebhookError("Missing saleor-event header", "MISSING_EVENT_HEADER"); + } + + const expected = allowedEvent.toLowerCase(); + + if (event !== expected) { + this.debug(`Wrong incoming request event: ${event}. Expected: ${expected}`); + + throw new WebhookError( + `Wrong incoming request event: ${event}. Expected: ${expected}`, + "WRONG_EVENT" + ); + } + + if (!signature) { + this.debug("No signature"); + + throw new WebhookError("Missing saleor-signature header", "MISSING_SIGNATURE_HEADER"); + } + + const rawBody = await this.adapter.getRawBody() + if (!rawBody) { + this.debug("Missing request body"); + + throw new WebhookError("Missing request body", "MISSING_REQUEST_BODY"); + } + + let parsedBody: unknown & { version?: string | null }; + + try { + parsedBody = JSON.parse(rawBody); + } catch { + this.debug("Request body cannot be parsed"); + + throw new WebhookError("Request body can't be parsed", "CANT_BE_PARSED"); + } + + let parsedSchemaVersion: number | null = null; + + try { + parsedSchemaVersion = parseSchemaVersion(parsedBody.version); + } catch { + this.debug("Schema version cannot be parsed"); + } + + /** + * Verify if the app is properly installed for given Saleor API URL + */ + const authData = await apl.get(saleorApiUrl); + + if (!authData) { + this.debug("APL didn't found auth data for %s", saleorApiUrl); + + throw new WebhookError( + `Can't find auth data for ${saleorApiUrl}. Please register the application`, + "NOT_REGISTERED" + ); + } + + /** + * Verify payload signature + * + * TODO: Add test for repeat verification scenario + */ + try { + this.debug("Will verify signature with JWKS saved in AuthData"); + + if (!authData.jwks) { + throw new Error("JWKS not found in AuthData"); + } + + await verifySignatureWithJwks(authData.jwks, signature, rawBody); + } catch { + this.debug("Request signature check failed. Refresh the JWKS cache and check again"); + + const newJwks = await fetchRemoteJwks(authData.saleorApiUrl).catch((e) => { + this.debug(e); + + throw new WebhookError("Fetching remote JWKS failed", "SIGNATURE_VERIFICATION_FAILED"); + }); + + this.debug("Fetched refreshed JWKS"); + + try { + this.debug("Second attempt to validate the signature JWKS, using fresh tokens from the API"); + + await verifySignatureWithJwks(newJwks, signature, rawBody); + + this.debug("Verification successful - update JWKS in the AuthData"); + + await apl.set({ ...authData, jwks: newJwks }); + } catch { + this.debug("Second attempt also ended with validation error. Reject the webhook"); + + throw new WebhookError( + "Request signature check failed", + "SIGNATURE_VERIFICATION_FAILED" + ); + } + } + + span.setStatus({ + code: SpanStatusCode.OK, + }); + + return { + baseUrl, + event, + payload: parsedBody as T, + authData, + schemaVersion: parsedSchemaVersion, + }; + } catch (err) { + const message = (err as Error)?.message ?? "Unknown error"; + + span.setStatus({ + code: SpanStatusCode.ERROR, + message, + }); + + throw err; + } finally { + span.end(); + } + } + ); + } +} diff --git a/src/handlers/shared/saleor-webhook.ts b/src/handlers/shared/saleor-webhook.ts index 935da295..10650ab1 100644 --- a/src/handlers/shared/saleor-webhook.ts +++ b/src/handlers/shared/saleor-webhook.ts @@ -1,6 +1,7 @@ +import { ResultStatusCodes } from "./generic-adapter-use-case-types"; import { SaleorWebhookError } from "./process-saleor-webhook"; -export const WebhookErrorCodeMap: Record = { +export const WebhookErrorCodeMap: Record = { OTHER: 500, MISSING_HOST_HEADER: 400, MISSING_DOMAIN_HEADER: 400, diff --git a/src/handlers/webhooks/abstract-webhook.ts b/src/handlers/webhooks/abstract-webhook.ts new file mode 100644 index 00000000..76ac1649 --- /dev/null +++ b/src/handlers/webhooks/abstract-webhook.ts @@ -0,0 +1,301 @@ +import { SpanKind, SpanStatusCode } from "@opentelemetry/api"; +import { ASTNode } from "graphql"; +import { NextApiRequest, NextApiResponse } from "next"; + +import { APL } from "@/APL"; +import { createDebug } from "@/debug"; +import { fetchRemoteJwks } from "@/fetch-remote-jwks"; +import { gqlAstToString } from "@/gql-ast-to-string"; +import { WebhookContext, WebhookError } from "@/handlers/shared/process-saleor-webhook"; +import { WebhookErrorCodeMap } from "@/handlers/shared/saleor-webhook"; +import { getOtelTracer } from "@/open-telemetry"; +import { AsyncWebhookEventType, SyncWebhookEventType, WebhookManifest } from "@/types"; +import { parseSchemaVersion } from "@/util"; +import { verifySignatureWithJwks } from "@/verify-signature"; + +import { ActionHandlerResult, PlatformAdapterInterface, PlatformAdapterMiddleware } from "../shared"; + +const debug = createDebug("SaleorWebhook"); + +export interface WebhookConfig { + name?: string; + webhookPath: string; + event: Event; + isActive?: boolean; + apl: APL; + onError?(error: WebhookError | Error, req: NextApiRequest, res: NextApiResponse): void; + formatErrorResponse?( + error: WebhookError | Error, + req: NextApiRequest, + res: NextApiResponse + ): Promise<{ + code: number; + body: object | string; + }>; + query: string | ASTNode; + /** + * @deprecated will be removed in 0.35.0, use query field instead + */ + subscriptionQueryAst?: ASTNode; +} + +export type NextWebhookApiHandler = ( + req: NextApiRequest, + res: NextApiResponse, + ctx: WebhookContext & TExtras +) => unknown | Promise; + +export abstract class SaleorWebhook< + Fn, + Request +> { + name: string; + + webhookPath: string; + + query: string | ASTNode; + + event: AsyncWebhookEventType | SyncWebhookEventType; + + isActive?: boolean; + + apl: APL; + + onError: WebhookConfig["onError"]; + + formatErrorResponse: WebhookConfig["formatErrorResponse"]; + + protected constructor(configuration: WebhookConfig, protected adapter: PlatformAdapterInterface, protected adapterMiddleware: PlatformAdapterMiddleware) { + const { + name, + webhookPath, + event, + query, + apl, + isActive = true, + subscriptionQueryAst, + } = configuration; + + this.name = name || `${event} webhook`; + /** + * Fallback subscriptionQueryAst to avoid breaking changes + * + * TODO Remove in 0.35.0 + */ + this.query = query ?? subscriptionQueryAst; + this.webhookPath = webhookPath; + this.event = event; + this.isActive = isActive; + this.apl = apl; + this.onError = configuration.onError; + this.formatErrorResponse = configuration.formatErrorResponse; + } + + private getTargetUrl(baseUrl: string) { + return new URL(this.webhookPath, baseUrl).href; + } + + /** + * Returns synchronous event manifest for this webhook. + * + * @param baseUrl Base URL used by your application + * @returns WebhookManifest + */ + protected getWebhookManifestBase(baseUrl: string): WebhookManifest { + return { + query: typeof this.query === "string" ? this.query : gqlAstToString(this.query), + name: this.name, + targetUrl: this.getTargetUrl(baseUrl), + isActive: this.isActive, + }; + } + + abstract getWebhookManifest(baseUrl: string): WebhookManifest; + + abstract createHandler(handlerFn: Fn): Fn; + + protected processWebhookRequest({ allowedEvent }: { allowedEvent: string }): Promise> { + const tracer = getOtelTracer(); + + return tracer.startActiveSpan( + "processSaleorWebhook", + { + kind: SpanKind.INTERNAL, + attributes: { + allowedEvent, + }, + }, + async (span) => { + try { + debug("Request processing started"); + + if (this.adapter.method !== "POST") { + debug("Wrong HTTP method"); + throw new WebhookError("Wrong request method, only POST allowed", "WRONG_METHOD"); + } + + const { event, signature, saleorApiUrl } = this.adapterMiddleware.getSaleorHeaders(); + const baseUrl = this.adapter.getBaseUrl(); + + if (!baseUrl) { + debug("Missing host header"); + throw new WebhookError("Missing host header", "MISSING_HOST_HEADER"); + } + + if (!saleorApiUrl) { + debug("Missing saleor-api-url header"); + throw new WebhookError("Missing saleor-api-url header", "MISSING_API_URL_HEADER"); + } + + if (!event) { + debug("Missing saleor-event header"); + throw new WebhookError("Missing saleor-event header", "MISSING_EVENT_HEADER"); + } + + const expected = allowedEvent.toLowerCase(); + + if (event !== expected) { + debug(`Wrong incoming request event: ${event}. Expected: ${expected}`); + + throw new WebhookError( + `Wrong incoming request event: ${event}. Expected: ${expected}`, + "WRONG_EVENT" + ); + } + + if (!signature) { + debug("No signature"); + + throw new WebhookError("Missing saleor-signature header", "MISSING_SIGNATURE_HEADER"); + } + + const rawBody = await this.adapter.getRawBody(); + + if (!rawBody) { + debug("Missing request body"); + + throw new WebhookError("Missing request body", "MISSING_REQUEST_BODY"); + } + + let parsedBody: unknown & { version?: string | null }; + + try { + parsedBody = JSON.parse(rawBody); + } catch { + debug("Request body cannot be parsed"); + + throw new WebhookError("Request body can't be parsed", "CANT_BE_PARSED"); + } + + let parsedSchemaVersion: number | null = null; + + try { + parsedSchemaVersion = parseSchemaVersion(parsedBody.version); + } catch { + debug("Schema version cannot be parsed"); + } + + /** + * Verify if the app is properly installed for given Saleor API URL + */ + const authData = await this.apl.get(saleorApiUrl); + + if (!authData) { + debug("APL didn't found auth data for %s", saleorApiUrl); + + throw new WebhookError( + `Can't find auth data for ${saleorApiUrl}. Please register the application`, + "NOT_REGISTERED" + ); + } + + /** + * Verify payload signature + * + * TODO: Add test for repeat verification scenario + */ + try { + debug("Will verify signature with JWKS saved in AuthData"); + + if (!authData.jwks) { + throw new Error("JWKS not found in AuthData"); + } + + await verifySignatureWithJwks(authData.jwks, signature, rawBody); + } catch { + debug("Request signature check failed. Refresh the JWKS cache and check again"); + + const newJwks = await fetchRemoteJwks(authData.saleorApiUrl).catch((e) => { + debug(e); + + throw new WebhookError("Fetching remote JWKS failed", "SIGNATURE_VERIFICATION_FAILED"); + }); + + debug("Fetched refreshed JWKS"); + + try { + debug("Second attempt to validate the signature JWKS, using fresh tokens from the API"); + + await verifySignatureWithJwks(newJwks, signature, rawBody); + + debug("Verification successful - update JWKS in the AuthData"); + + await this.apl.set({ ...authData, jwks: newJwks }); + } catch { + debug("Second attempt also ended with validation error. Reject the webhook"); + + throw new WebhookError( + "Request signature check failed", + "SIGNATURE_VERIFICATION_FAILED" + ); + } + } + + span.setStatus({ + code: SpanStatusCode.OK, + }); + + return { + baseUrl, + event, + payload: parsedBody as T, + authData, + schemaVersion: parsedSchemaVersion, + }; + } catch (err) { + const message = (err as Error)?.message ?? "Unknown error"; + + span.setStatus({ + code: SpanStatusCode.ERROR, + message, + }); + + throw err; + } finally { + span.end(); + } + } + ); + } + + protected getDefaultErrorResponse(error: WebhookError | Error): ActionHandlerResult { + if (error instanceof WebhookError) { + const status = WebhookErrorCodeMap[error.errorType] || 400; + return { + body: { + type: error.errorType, + message: error.message + }, + status, + bodyType: "json" + }; + } + + return { + body: "Unexpected server error", + bodyType: "string", + status: 500 + } + }; + +} From f146bc388eaa4b9463ea78ab78f87b2c93e7123f Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 24 Jan 2025 09:41:12 +0100 Subject: [PATCH 49/58] Add common logic for Saleor webhook validation using adapter --- .../next/saleor-webhooks/saleor-webhook.ts | 32 +++++++------- .../shared/saleor-webhook-validator.ts | 43 +++++++++++++------ 2 files changed, 46 insertions(+), 29 deletions(-) diff --git a/src/handlers/platforms/next/saleor-webhooks/saleor-webhook.ts b/src/handlers/platforms/next/saleor-webhooks/saleor-webhook.ts index a56a8876..433800a1 100644 --- a/src/handlers/platforms/next/saleor-webhooks/saleor-webhook.ts +++ b/src/handlers/platforms/next/saleor-webhooks/saleor-webhook.ts @@ -23,7 +23,7 @@ export interface WebhookConfig = ( req: NextApiRequest, res: NextApiResponse, - ctx: WebhookContext & TExtras + ctx: WebhookContext & TExtras, ) => unknown | Promise; export abstract class SaleorWebhook< TPayload = unknown, - TExtras extends Record = {} + TExtras extends Record = {}, > { protected abstract eventType: "async" | "sync"; @@ -136,12 +136,18 @@ export abstract class SaleorWebhook< const webhookValidator = new SaleorWebhookValidator(adapter); debug(`Handler for webhook ${this.name} called`); - const validationResult = await webhookValidator.validateRequest({ allowedEvent: this.event, apl: this.apl }); + const validationResult = await webhookValidator.validateRequest({ + allowedEvent: this.event, + apl: this.apl, + }); if (validationResult.result === "ok") { debug("Incoming request validated. Call handlerFn"); - return handlerFn(req, res, { ...(this.extraContext ?? ({} as TExtras)), ...validationResult.context }); + return handlerFn(req, res, { + ...(this.extraContext ?? ({} as TExtras)), + ...validationResult.context, + }); } debug(`Unexpected error during processing the webhook ${this.name}`); @@ -157,18 +163,15 @@ export abstract class SaleorWebhook< if (this.formatErrorResponse) { const { code, body } = await this.formatErrorResponse(e, req, res); - res.status(code).send(body); - - return; + return res.status(code).send(body); } - res.status(WebhookErrorCodeMap[e.errorType] || 400).send({ + return res.status(WebhookErrorCodeMap[e.errorType] || 400).send({ error: { type: e.errorType, message: e.message, }, }); - return; } debug("Unexpected error: %O", e); @@ -179,15 +182,10 @@ export abstract class SaleorWebhook< if (this.formatErrorResponse) { const { code, body } = await this.formatErrorResponse(e, req, res); - res.status(code).send(body); - - return; + return res.status(code).send(body); } - res.status(500).end(); - - - + return res.status(500).end(); }; } } diff --git a/src/handlers/shared/saleor-webhook-validator.ts b/src/handlers/shared/saleor-webhook-validator.ts index b71af2b3..b22b9e04 100644 --- a/src/handlers/shared/saleor-webhook-validator.ts +++ b/src/handlers/shared/saleor-webhook-validator.ts @@ -1,7 +1,7 @@ import { SpanKind, SpanStatusCode } from "@opentelemetry/api"; import { APL } from "@/APL"; -import { createDebug, } from "@/debug"; +import { createDebug } from "@/debug"; import { fetchRemoteJwks } from "@/fetch-remote-jwks"; import { getOtelTracer } from "@/open-telemetry"; import { parseSchemaVersion } from "@/util"; @@ -11,18 +11,26 @@ import { PlatformAdapterMiddleware } from "./adapter-middleware"; import { PlatformAdapterInterface } from "./generic-adapter-use-case-types"; import { WebhookContext, WebhookError } from "./process-saleor-webhook"; -type WebhookValidationResult = { result: "ok", context: WebhookContext } | { result: "failure", error: WebhookError }; +type WebhookValidationResult = + | { result: "ok"; context: WebhookContext } + | { result: "failure"; error: WebhookError }; export class SaleorWebhookValidator { private debug = createDebug("processProtectedHandler"); private tracer = getOtelTracer(); - constructor(private adapter: PlatformAdapterInterface) { } + constructor(private adapter: PlatformAdapterInterface) {} private adapterMiddleware = new PlatformAdapterMiddleware(this.adapter); - async validateRequest({ allowedEvent, apl }: { allowedEvent: string, apl: APL }): Promise> { + async validateRequest({ + allowedEvent, + apl, + }: { + allowedEvent: string; + apl: APL; + }): Promise> { try { const context = await this.validateRequestOrThrowError({ allowedEvent, apl }); @@ -38,7 +46,13 @@ export class SaleorWebhookValidator { } } - private async validateRequestOrThrowError({ allowedEvent, apl }: { allowedEvent: string, apl: APL }): Promise> { + private async validateRequestOrThrowError({ + allowedEvent, + apl, + }: { + allowedEvent: string; + apl: APL; + }): Promise> { return this.tracer.startActiveSpan( "processSaleorWebhook", { @@ -81,7 +95,7 @@ export class SaleorWebhookValidator { throw new WebhookError( `Wrong incoming request event: ${event}. Expected: ${expected}`, - "WRONG_EVENT" + "WRONG_EVENT", ); } @@ -91,7 +105,7 @@ export class SaleorWebhookValidator { throw new WebhookError("Missing saleor-signature header", "MISSING_SIGNATURE_HEADER"); } - const rawBody = await this.adapter.getRawBody() + const rawBody = await this.adapter.getRawBody(); if (!rawBody) { this.debug("Missing request body"); @@ -126,7 +140,7 @@ export class SaleorWebhookValidator { throw new WebhookError( `Can't find auth data for ${saleorApiUrl}. Please register the application`, - "NOT_REGISTERED" + "NOT_REGISTERED", ); } @@ -149,13 +163,18 @@ export class SaleorWebhookValidator { const newJwks = await fetchRemoteJwks(authData.saleorApiUrl).catch((e) => { this.debug(e); - throw new WebhookError("Fetching remote JWKS failed", "SIGNATURE_VERIFICATION_FAILED"); + throw new WebhookError( + "Fetching remote JWKS failed", + "SIGNATURE_VERIFICATION_FAILED", + ); }); this.debug("Fetched refreshed JWKS"); try { - this.debug("Second attempt to validate the signature JWKS, using fresh tokens from the API"); + this.debug( + "Second attempt to validate the signature JWKS, using fresh tokens from the API", + ); await verifySignatureWithJwks(newJwks, signature, rawBody); @@ -167,7 +186,7 @@ export class SaleorWebhookValidator { throw new WebhookError( "Request signature check failed", - "SIGNATURE_VERIFICATION_FAILED" + "SIGNATURE_VERIFICATION_FAILED", ); } } @@ -195,7 +214,7 @@ export class SaleorWebhookValidator { } finally { span.end(); } - } + }, ); } } From efd0f8d70694757b3fdb269aee1ad3ae554415e1 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 24 Jan 2025 09:47:11 +0100 Subject: [PATCH 50/58] Add webhok impl for fetch api --- .../saleor-webhooks/process-saleor-webhook.ts | 162 ------------------ .../saleor-webhooks/saleor-async-webhook.ts | 4 +- .../saleor-webhooks/saleor-sync-webhook.ts | 4 +- .../saleor-webhooks/saleor-webhook.ts | 110 ++++++------ .../saleor-webhooks/process-saleor-webhook.ts | 12 +- 5 files changed, 68 insertions(+), 224 deletions(-) delete mode 100644 src/handlers/platforms/fetch-api/saleor-webhooks/process-saleor-webhook.ts diff --git a/src/handlers/platforms/fetch-api/saleor-webhooks/process-saleor-webhook.ts b/src/handlers/platforms/fetch-api/saleor-webhooks/process-saleor-webhook.ts deleted file mode 100644 index b4d14336..00000000 --- a/src/handlers/platforms/fetch-api/saleor-webhooks/process-saleor-webhook.ts +++ /dev/null @@ -1,162 +0,0 @@ -import { APL } from "@/APL"; -import { createDebug } from "@/debug"; -import { fetchRemoteJwks } from "@/fetch-remote-jwks"; -import { WebhookContext, WebhookError } from "@/handlers/shared/process-saleor-webhook"; -import { getBaseUrlFetchAPI, getSaleorHeadersFetchAPI } from "@/headers"; -import { parseSchemaVersion } from "@/util"; -import { verifySignatureWithJwks } from "@/verify-signature"; - -const debug = createDebug("WebAPI:processSaleorWebhook"); - -interface ProcessSaleorWebhookArgs { - req: Request; - apl: APL; - allowedEvent: string; -} - -export const processSaleorWebhook = async ({ - req, - apl, - allowedEvent, -}: ProcessSaleorWebhookArgs): Promise> => { - // TODO: Add OTEL - - try { - debug("Request processing started"); - - if (req.method !== "POST") { - debug("Wrong HTTP method"); - throw new WebhookError("Wrong request method, only POST allowed", "WRONG_METHOD"); - } - - const { event, signature, saleorApiUrl } = getSaleorHeadersFetchAPI(req.headers); - const baseUrl = getBaseUrlFetchAPI(req); - - if (!baseUrl) { - debug("Missing host header"); - throw new WebhookError("Missing host header", "MISSING_HOST_HEADER"); - } - - if (!saleorApiUrl) { - debug("Missing saleor-api-url header"); - throw new WebhookError("Missing saleor-api-url header", "MISSING_API_URL_HEADER"); - } - - if (!event) { - debug("Missing saleor-event header"); - throw new WebhookError("Missing saleor-event header", "MISSING_EVENT_HEADER"); - } - - const expected = allowedEvent.toLowerCase(); - - if (event !== expected) { - debug(`Wrong incoming request event: ${event}. Expected: ${expected}`); - - throw new WebhookError( - `Wrong incoming request event: ${event}. Expected: ${expected}`, - "WRONG_EVENT" - ); - } - - if (!signature) { - debug("No signature"); - - throw new WebhookError("Missing saleor-signature header", "MISSING_SIGNATURE_HEADER"); - } - - let rawBody: string; - - try { - rawBody = await req.text(); - } catch (err) { - throw new WebhookError("Error reading request body", "CANT_BE_PARSED"); - } - - if (!rawBody) { - debug("Missing request body"); - - throw new WebhookError("Missing request body", "MISSING_REQUEST_BODY"); - } - - let parsedBody: unknown & { version?: string | null }; - - try { - parsedBody = JSON.parse(rawBody); - } catch (err) { - throw new WebhookError("Request body can't be parsed", "CANT_BE_PARSED"); - } - - let parsedSchemaVersion: number | null = null; - - try { - parsedSchemaVersion = parseSchemaVersion(parsedBody.version); - } catch { - debug("Schema version cannot be parsed"); - } - - /** - * Verify if the app is properly installed for given Saleor API URL - */ - const authData = await apl.get(saleorApiUrl); - - if (!authData) { - debug("APL didn't found auth data for %s", saleorApiUrl); - - throw new WebhookError( - `Can't find auth data for ${saleorApiUrl}. Please register the application`, - "NOT_REGISTERED" - ); - } - - /** - * Verify payload signature - * - * TODO: Add test for repeat verification scenario - */ - try { - debug("Will verify signature with JWKS saved in AuthData"); - - if (!authData.jwks) { - throw new Error("JWKS not found in AuthData"); - } - - await verifySignatureWithJwks(authData.jwks, signature, rawBody); - } catch { - debug("Request signature check failed. Refresh the JWKS cache and check again"); - - const newJwks = await fetchRemoteJwks(authData.saleorApiUrl).catch((e) => { - debug(e); - - throw new WebhookError("Fetching remote JWKS failed", "SIGNATURE_VERIFICATION_FAILED"); - }); - - debug("Fetched refreshed JWKS"); - - try { - debug("Second attempt to validate the signature JWKS, using fresh tokens from the API"); - - await verifySignatureWithJwks(newJwks, signature, rawBody); - - debug("Verification successful - update JWKS in the AuthData"); - - await apl.set({ ...authData, jwks: newJwks }); - } catch { - debug("Second attempt also ended with validation error. Reject the webhook"); - - throw new WebhookError("Request signature check failed", "SIGNATURE_VERIFICATION_FAILED"); - } - } - - return { - baseUrl, - event, - payload: parsedBody as T, - authData, - schemaVersion: parsedSchemaVersion, - }; - } catch (err) { - debug("Unexpected error: %O", err); - - throw err; - } -}; diff --git a/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-async-webhook.ts b/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-async-webhook.ts index dc84eeaf..f30217ee 100644 --- a/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-async-webhook.ts +++ b/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-async-webhook.ts @@ -26,7 +26,7 @@ export class SaleorAsyncWebhook extends SaleorWebApiWebhook< asyncEvent?: AsyncWebhookEventType; event?: AsyncWebhookEventType; query?: string | ASTNode; - } + }, ) { if (!configuration.event && !configuration.asyncEvent) { throw new Error("event or asyncEvent must be provided. asyncEvent is deprecated"); @@ -34,7 +34,7 @@ export class SaleorAsyncWebhook extends SaleorWebApiWebhook< if (!configuration.query && !configuration.subscriptionQueryAst) { throw new Error( - "query or subscriptionQueryAst must be provided. subscriptionQueryAst is deprecated" + "query or subscriptionQueryAst must be provided. subscriptionQueryAst is deprecated", ); } diff --git a/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-sync-webhook.ts b/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-sync-webhook.ts index 1b993da8..02bf5b67 100644 --- a/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-sync-webhook.ts +++ b/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-sync-webhook.ts @@ -13,7 +13,7 @@ type InjectedContext = { }; export class SaleorSyncWebhook< TPayload = unknown, - TEvent extends SyncWebhookEventType = SyncWebhookEventType + TEvent extends SyncWebhookEventType = SyncWebhookEventType, > extends SaleorWebApiWebhook> { readonly event: TEvent; @@ -35,7 +35,7 @@ export class SaleorSyncWebhook< { buildResponse: typeof buildSyncWebhookResponsePayload; } - > + >, ): WebApiRouteHandler { return super.createHandler(handlerFn); } diff --git a/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-webhook.ts b/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-webhook.ts index d9352e0a..ceee3134 100644 --- a/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-webhook.ts +++ b/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-webhook.ts @@ -5,9 +5,10 @@ import { createDebug } from "@/debug"; import { gqlAstToString } from "@/gql-ast-to-string"; import { WebhookContext, WebhookError } from "@/handlers/shared/process-saleor-webhook"; import { WebhookErrorCodeMap } from "@/handlers/shared/saleor-webhook"; +import { SaleorWebhookValidator } from "@/handlers/shared/saleor-webhook-validator"; import { AsyncWebhookEventType, SyncWebhookEventType, WebhookManifest } from "@/types"; -import { processSaleorWebhook } from "./process-saleor-webhook"; +import { WebApiAdapter } from "../platform-adapter"; const debug = createDebug("SaleorWebhook"); @@ -20,7 +21,7 @@ export interface WebhookConfig Response | Promise = ( req: Request, - ctx: WebhookContext & TExtras + ctx: WebhookContext & TExtras, ) => Response | Promise; export abstract class SaleorWebApiWebhook< TPayload = unknown, - TExtras extends Record = {} + TExtras extends Record = {}, > { protected abstract eventType: "async" | "sync"; @@ -133,57 +134,60 @@ export abstract class SaleorWebApiWebhook< createHandler(handlerFn: SaleorWebhookHandler): WebApiRouteHandler { return async (req) => { debug(`Handler for webhook ${this.name} called`); + const adapter = new WebApiAdapter(req); + const webhookValidator = new SaleorWebhookValidator(adapter); - return processSaleorWebhook({ - req, - apl: this.apl, - allowedEvent: this.event, - }) - .then(async (context) => { - debug("Incoming request validated. Call handlerFn"); - - return handlerFn(req, { ...(this.extraContext ?? ({} as TExtras)), ...context }); - }) - .catch(async (e) => { - debug(`Unexpected error during processing the webhook ${this.name}`); - - if (e instanceof WebhookError) { - debug(`Validation error: ${e.message}`); - - if (this.onError) { - this.onError(e, req); - } - - if (this.formatErrorResponse) { - const { code, body } = await this.formatErrorResponse(e, req); - - return new Response(body, { status: code }); - } - - return new Response( - JSON.stringify({ - error: { - type: e.errorType, - message: e.message, - }, - }), - { status: WebhookErrorCodeMap[e.errorType] || 400 } - ); - } - debug("Unexpected error: %O", e); - - if (this.onError) { - this.onError(e, req); - } - - if (this.formatErrorResponse) { - const { code, body } = await this.formatErrorResponse(e, req); - - return new Response(body, { status: code }); - } - - return new Response("Unexpected error while handling request", { status: 500 }); + const validationResult = await webhookValidator.validateRequest({ allowedEvent: this.event, apl: this.apl }); + + if (validationResult.result === "ok") { + debug("Incoming request validated. Call handlerFn"); + + return handlerFn(req, { + ...(this.extraContext ?? ({} as TExtras)), + ...validationResult.context, }); + } + + const { error } = validationResult; + + debug(`Unexpected error during processing the webhook ${this.name}`); + + if (error instanceof WebhookError) { + debug(`Validation error: ${error.message}`); + + if (this.onError) { + this.onError(error, req); + } + + if (this.formatErrorResponse) { + const { code, body } = await this.formatErrorResponse(error, req); + + return new Response(body, { status: code }); + } + + return new Response( + JSON.stringify({ + error: { + type: error.errorType, + message: error.message, + }, + }), + { status: WebhookErrorCodeMap[error.errorType] || 400 }, + ); + } + debug("Unexpected error: %O", error); + + if (this.onError) { + this.onError(error, req); + } + + if (this.formatErrorResponse) { + const { code, body } = await this.formatErrorResponse(error, req); + + return new Response(body, { status: code }); + } + + return new Response("Unexpected error while handling request", { status: 500 }); }; } } diff --git a/src/handlers/platforms/next/saleor-webhooks/process-saleor-webhook.ts b/src/handlers/platforms/next/saleor-webhooks/process-saleor-webhook.ts index f347ad2f..f62e4b70 100644 --- a/src/handlers/platforms/next/saleor-webhooks/process-saleor-webhook.ts +++ b/src/handlers/platforms/next/saleor-webhooks/process-saleor-webhook.ts @@ -20,13 +20,15 @@ interface ProcessSaleorWebhookArgs { } type ProcessSaleorWebhook = ( - props: ProcessSaleorWebhookArgs + props: ProcessSaleorWebhookArgs, ) => Promise>; /** * Perform security checks on given request and return WebhookContext object. * In case of validation issues, instance of the WebhookError will be thrown. * + * @deprecated + * * @returns WebhookContext */ export const processSaleorWebhook: ProcessSaleorWebhook = async ({ @@ -78,7 +80,7 @@ export const processSaleorWebhook: ProcessSaleorWebhook = async ({ throw new WebhookError( `Wrong incoming request event: ${event}. Expected: ${expected}`, - "WRONG_EVENT" + "WRONG_EVENT", ); } @@ -127,7 +129,7 @@ export const processSaleorWebhook: ProcessSaleorWebhook = async ({ throw new WebhookError( `Can't find auth data for ${saleorApiUrl}. Please register the application`, - "NOT_REGISTERED" + "NOT_REGISTERED", ); } @@ -168,7 +170,7 @@ export const processSaleorWebhook: ProcessSaleorWebhook = async ({ throw new WebhookError( "Request signature check failed", - "SIGNATURE_VERIFICATION_FAILED" + "SIGNATURE_VERIFICATION_FAILED", ); } } @@ -196,6 +198,6 @@ export const processSaleorWebhook: ProcessSaleorWebhook = async ({ } finally { span.end(); } - } + }, ); }; From 9462deb3d66af8e17e9c3817b271b316a3c1c809 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 24 Jan 2025 11:43:17 +0100 Subject: [PATCH 51/58] Add generic webhook handler, add aws lambda webhook --- .../saleor-webhooks/saleor-async-webhook.ts | 0 .../saleor-webhooks/saleor-sync-webhook.ts | 0 .../saleor-webhooks/saleor-webhook.ts | 195 +++++++++++++++++ .../saleor-webhooks/saleor-webhook.ts | 20 +- .../next/saleor-webhooks/saleor-webhook.ts | 6 +- src/handlers/shared/generic-saleor-webhook.ts | 207 ++++++++++++++++++ .../shared/saleor-webhook-validator.ts | 12 +- 7 files changed, 421 insertions(+), 19 deletions(-) create mode 100644 src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-async-webhook.ts create mode 100644 src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-sync-webhook.ts create mode 100644 src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-webhook.ts create mode 100644 src/handlers/shared/generic-saleor-webhook.ts diff --git a/src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-async-webhook.ts b/src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-async-webhook.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-sync-webhook.ts b/src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-sync-webhook.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-webhook.ts b/src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-webhook.ts new file mode 100644 index 00000000..41b25cd4 --- /dev/null +++ b/src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-webhook.ts @@ -0,0 +1,195 @@ +import { Context } from "aws-lambda"; +import { ASTNode } from "graphql"; + +import { APL } from "@/APL"; +import { createDebug } from "@/debug"; +import { gqlAstToString } from "@/gql-ast-to-string"; +import { WebhookContext, WebhookError } from "@/handlers/shared/process-saleor-webhook"; +import { WebhookErrorCodeMap } from "@/handlers/shared/saleor-webhook"; +import { SaleorWebhookValidator } from "@/handlers/shared/saleor-webhook-validator"; +import { AsyncWebhookEventType, SyncWebhookEventType, WebhookManifest } from "@/types"; + +import { AwsLambdaAdapter, AWSLambdaHandler, AwsLambdaHandlerInput } from "../platform-adapter"; + +const debug = createDebug("SaleorWebhook"); + +export interface WebhookConfig { + name?: string; + webhookPath: string; + event: Event; + isActive?: boolean; + apl: APL; + onError?(error: WebhookError | Error, event: AwsLambdaHandlerInput): void; + formatErrorResponse?( + error: WebhookError | Error, + event: AwsLambdaHandlerInput + ): Promise<{ + code: number; + body: string; + }>; + query: string | ASTNode; + /** + * @deprecated will be removed in 0.35.0, use query field instead + */ + subscriptionQueryAst?: ASTNode; +} + +/** Function type provided by consumer in `SaleorWebApiWebhook.createHandler` */ +export type SaleorWebhookHandler = ( + event: AwsLambdaHandlerInput, + context: Context, + ctx: WebhookContext & TExtras +) => Response | Promise; + +export abstract class SaleorWebApiWebhook< + TPayload = unknown, + TExtras extends Record = {} +> { + protected abstract eventType: "async" | "sync"; + + protected extraContext?: TExtras; + + name: string; + + webhookPath: string; + + query: string | ASTNode; + + event: AsyncWebhookEventType | SyncWebhookEventType; + + isActive?: boolean; + + apl: APL; + + onError: WebhookConfig["onError"]; + + formatErrorResponse: WebhookConfig["formatErrorResponse"]; + + protected constructor(configuration: WebhookConfig) { + const { + name, + webhookPath, + event, + query, + apl, + isActive = true, + subscriptionQueryAst, + } = configuration; + + this.name = name || `${event} webhook`; + /** + * Fallback subscriptionQueryAst to avoid breaking changes + * + * TODO Remove in 0.35.0 + */ + this.query = query ?? subscriptionQueryAst; + this.webhookPath = webhookPath; + this.event = event; + this.isActive = isActive; + this.apl = apl; + this.onError = configuration.onError; + this.formatErrorResponse = configuration.formatErrorResponse; + } + + private getTargetUrl(baseUrl: string) { + return new URL(this.webhookPath, baseUrl).href; + } + + /** + * Returns synchronous event manifest for this webhook. + * + * @param baseUrl Base URL used by your application + * @returns WebhookManifest + */ + getWebhookManifest(baseUrl: string): WebhookManifest { + const manifestBase: Omit = { + query: typeof this.query === "string" ? this.query : gqlAstToString(this.query), + name: this.name, + targetUrl: this.getTargetUrl(baseUrl), + isActive: this.isActive, + }; + + switch (this.eventType) { + case "async": + return { + ...manifestBase, + asyncEvents: [this.event as AsyncWebhookEventType], + }; + case "sync": + return { + ...manifestBase, + syncEvents: [this.event as SyncWebhookEventType], + }; + default: { + throw new Error("Class extended incorrectly"); + } + } + } + + /** + * Wraps provided function, to ensure incoming request comes from registered Saleor instance. + * Also provides additional `context` object containing typed payload and request properties. + */ + createHandler(handlerFn: SaleorWebhookHandler): AWSLambdaHandler { + return async (event, context) => { + debug(`Handler for webhook ${this.name} called`); + const adapter = new AwsLambdaAdapter(event, context); + const webhookValidator = new SaleorWebhookValidator(adapter); + + const validationResult = await webhookValidator.validateRequest({ + allowedEvent: this.event, + apl: this.apl, + }); + + if (validationResult.result === "ok") { + debug("Incoming request validated. Call handlerFn"); + + return handlerFn(event, context, { + ...(this.extraContext ?? ({} as TExtras)), + ...validationResult.context, + }); + } + + const { error } = validationResult; + + debug(`Unexpected error during processing the webhook ${this.name}`); + + if (error instanceof WebhookError) { + debug(`Validation error: ${error.message}`); + + if (this.onError) { + this.onError(error, event); + } + + if (this.formatErrorResponse) { + const { code, body } = await this.formatErrorResponse(error, event); + + return new Response(body, { status: code }); + } + + return new Response( + JSON.stringify({ + error: { + type: error.errorType, + message: error.message, + }, + }), + { status: WebhookErrorCodeMap[error.errorType] || 400 } + ); + } + debug("Unexpected error: %O", error); + + if (this.onError) { + this.onError(error, event); + } + + if (this.formatErrorResponse) { + const { code, body } = await this.formatErrorResponse(error, event); + + return new Response(body, { status: code }); + } + + return new Response("Unexpected error while handling request", { status: 500 }); + }; + } +} diff --git a/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-webhook.ts b/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-webhook.ts index ceee3134..ba2ce278 100644 --- a/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-webhook.ts +++ b/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-webhook.ts @@ -8,7 +8,7 @@ import { WebhookErrorCodeMap } from "@/handlers/shared/saleor-webhook"; import { SaleorWebhookValidator } from "@/handlers/shared/saleor-webhook-validator"; import { AsyncWebhookEventType, SyncWebhookEventType, WebhookManifest } from "@/types"; -import { WebApiAdapter } from "../platform-adapter"; +import { WebApiAdapter, WebApiHandler } from "../platform-adapter"; const debug = createDebug("SaleorWebhook"); @@ -21,7 +21,7 @@ export interface WebhookConfig Response | Promise; - /** Function type provided by consumer in `SaleorWebApiWebhook.createHandler` */ export type SaleorWebhookHandler = ( req: Request, - ctx: WebhookContext & TExtras, + ctx: WebhookContext & TExtras ) => Response | Promise; export abstract class SaleorWebApiWebhook< TPayload = unknown, - TExtras extends Record = {}, + TExtras extends Record = {} > { protected abstract eventType: "async" | "sync"; @@ -131,13 +128,16 @@ export abstract class SaleorWebApiWebhook< * Wraps provided function, to ensure incoming request comes from registered Saleor instance. * Also provides additional `context` object containing typed payload and request properties. */ - createHandler(handlerFn: SaleorWebhookHandler): WebApiRouteHandler { + createHandler(handlerFn: SaleorWebhookHandler): WebApiHandler { return async (req) => { debug(`Handler for webhook ${this.name} called`); const adapter = new WebApiAdapter(req); const webhookValidator = new SaleorWebhookValidator(adapter); - const validationResult = await webhookValidator.validateRequest({ allowedEvent: this.event, apl: this.apl }); + const validationResult = await webhookValidator.validateRequest({ + allowedEvent: this.event, + apl: this.apl, + }); if (validationResult.result === "ok") { debug("Incoming request validated. Call handlerFn"); @@ -172,7 +172,7 @@ export abstract class SaleorWebApiWebhook< message: error.message, }, }), - { status: WebhookErrorCodeMap[error.errorType] || 400 }, + { status: WebhookErrorCodeMap[error.errorType] || 400 } ); } debug("Unexpected error: %O", error); diff --git a/src/handlers/platforms/next/saleor-webhooks/saleor-webhook.ts b/src/handlers/platforms/next/saleor-webhooks/saleor-webhook.ts index 433800a1..5bd3e5c8 100644 --- a/src/handlers/platforms/next/saleor-webhooks/saleor-webhook.ts +++ b/src/handlers/platforms/next/saleor-webhooks/saleor-webhook.ts @@ -23,7 +23,7 @@ export interface WebhookConfig = ( req: NextApiRequest, res: NextApiResponse, - ctx: WebhookContext & TExtras, + ctx: WebhookContext & TExtras ) => unknown | Promise; export abstract class SaleorWebhook< TPayload = unknown, - TExtras extends Record = {}, + TExtras extends Record = {} > { protected abstract eventType: "async" | "sync"; diff --git a/src/handlers/shared/generic-saleor-webhook.ts b/src/handlers/shared/generic-saleor-webhook.ts new file mode 100644 index 00000000..76b7ba6e --- /dev/null +++ b/src/handlers/shared/generic-saleor-webhook.ts @@ -0,0 +1,207 @@ +import { ASTNode } from "graphql"; + +import { APL } from "@/APL"; +import { createDebug } from "@/debug"; +import { gqlAstToString } from "@/gql-ast-to-string"; +import { PlatformAdapterInterface } from "@/handlers/shared"; +import { WebhookContext, WebhookError } from "@/handlers/shared/process-saleor-webhook"; +import { WebhookErrorCodeMap } from "@/handlers/shared/saleor-webhook"; +import { SaleorWebhookValidator } from "@/handlers/shared/saleor-webhook-validator"; +import { AsyncWebhookEventType, SyncWebhookEventType, WebhookManifest } from "@/types"; + +const debug = createDebug("SaleorWebhook"); + +export interface WebhookConfig { + name?: string; + webhookPath: string; + event: Event; + isActive?: boolean; + apl: APL; + onError?(error: WebhookError | Error, request: RequestType): void; + formatErrorResponse?( + error: WebhookError | Error, + request: RequestType + ): Promise<{ + code: number; + body: string; + }>; + query: string | ASTNode; + /** + * @deprecated will be removed in 0.35.0, use query field instead + */ + subscriptionQueryAst?: ASTNode; +} + +export abstract class GenericSaleorWebApiWebhook< + RequestType, + TPayload = unknown, + TExtras extends Record = {} +> { + protected abstract eventType: "async" | "sync"; + + protected extraContext?: TExtras; + + name: string; + + webhookPath: string; + + query: string | ASTNode; + + event: AsyncWebhookEventType | SyncWebhookEventType; + + isActive?: boolean; + + apl: APL; + + onError: WebhookConfig["onError"]; + + formatErrorResponse: WebhookConfig["formatErrorResponse"]; + + protected constructor(configuration: WebhookConfig) { + const { + name, + webhookPath, + event, + query, + apl, + isActive = true, + subscriptionQueryAst, + } = configuration; + + this.name = name || `${event} webhook`; + /** + * Fallback subscriptionQueryAst to avoid breaking changes + * + * TODO Remove in 0.35.0 + */ + this.query = query ?? subscriptionQueryAst; + this.webhookPath = webhookPath; + this.event = event; + this.isActive = isActive; + this.apl = apl; + this.onError = configuration.onError; + this.formatErrorResponse = configuration.formatErrorResponse; + } + + private getTargetUrl(baseUrl: string) { + return new URL(this.webhookPath, baseUrl).href; + } + + /** + * Returns synchronous event manifest for this webhook. + * + * @param baseUrl Base URL used by your application + * @returns WebhookManifest + */ + getWebhookManifest(baseUrl: string): WebhookManifest { + const manifestBase: Omit = { + query: typeof this.query === "string" ? this.query : gqlAstToString(this.query), + name: this.name, + targetUrl: this.getTargetUrl(baseUrl), + isActive: this.isActive, + }; + + switch (this.eventType) { + case "async": + return { + ...manifestBase, + asyncEvents: [this.event as AsyncWebhookEventType], + }; + case "sync": + return { + ...manifestBase, + syncEvents: [this.event as SyncWebhookEventType], + }; + default: { + throw new Error("Class extended incorrectly"); + } + } + } + + protected async prepareRequest>({ + adapter, + validator, + }: { + adapter: A; + validator: SaleorWebhookValidator; + callback: (adapter: A, context: WebhookContext) => unknown; + }): Promise< + | { result: "callHandler"; context: WebhookContext } + | { result: "sendResponse"; response: unknown } + > { + const validationResult = await validator.validateRequest({ + allowedEvent: this.event, + apl: this.apl, + }); + + if (validationResult.result === "ok") { + return { result: "callHandler", context: validationResult.context }; + } + + const { error } = validationResult; + + debug(`Unexpected error during processing the webhook ${this.name}`); + + if (error instanceof WebhookError) { + debug(`Validation error: ${error.message}`); + + if (this.onError) { + this.onError(error, adapter.request); + } + + if (this.formatErrorResponse) { + const { code, body } = await this.formatErrorResponse(error, adapter.request); + + return { + result: "sendResponse", + response: adapter.send({ + status: code, + body, + bodyType: "string", + }), + }; + } + + return { + result: "sendResponse", + response: adapter.send({ + bodyType: "json", + body: { + error: { + type: error.errorType, + message: error.message, + }, + }, + status: WebhookErrorCodeMap[error.errorType] || 400, + }), + }; + } + debug("Unexpected error: %O", error); + + if (this.onError) { + this.onError(error, adapter.request); + } + + if (this.formatErrorResponse) { + const { code, body } = await this.formatErrorResponse(error, adapter.request); + + return { + result: "sendResponse", + response: adapter.send({ + status: code, + body, + bodyType: "string", + }), + }; + } + + return { + result: "sendResponse", + response: adapter.send({ + status: 500, + body: "Unexpected error while handling request", + bodyType: "string", + }), + }; + } +} diff --git a/src/handlers/shared/saleor-webhook-validator.ts b/src/handlers/shared/saleor-webhook-validator.ts index b22b9e04..c5e03ccb 100644 --- a/src/handlers/shared/saleor-webhook-validator.ts +++ b/src/handlers/shared/saleor-webhook-validator.ts @@ -95,7 +95,7 @@ export class SaleorWebhookValidator { throw new WebhookError( `Wrong incoming request event: ${event}. Expected: ${expected}`, - "WRONG_EVENT", + "WRONG_EVENT" ); } @@ -140,7 +140,7 @@ export class SaleorWebhookValidator { throw new WebhookError( `Can't find auth data for ${saleorApiUrl}. Please register the application`, - "NOT_REGISTERED", + "NOT_REGISTERED" ); } @@ -165,7 +165,7 @@ export class SaleorWebhookValidator { throw new WebhookError( "Fetching remote JWKS failed", - "SIGNATURE_VERIFICATION_FAILED", + "SIGNATURE_VERIFICATION_FAILED" ); }); @@ -173,7 +173,7 @@ export class SaleorWebhookValidator { try { this.debug( - "Second attempt to validate the signature JWKS, using fresh tokens from the API", + "Second attempt to validate the signature JWKS, using fresh tokens from the API" ); await verifySignatureWithJwks(newJwks, signature, rawBody); @@ -186,7 +186,7 @@ export class SaleorWebhookValidator { throw new WebhookError( "Request signature check failed", - "SIGNATURE_VERIFICATION_FAILED", + "SIGNATURE_VERIFICATION_FAILED" ); } } @@ -214,7 +214,7 @@ export class SaleorWebhookValidator { } finally { span.end(); } - }, + } ); } } From 966defe9ccdfa1b1fa8d6144900d5f46d6f3ec8d Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 24 Jan 2025 12:31:10 +0100 Subject: [PATCH 52/58] Add AWS Lambda Saleor webhook, update generic types, fix types web api --- .../saleor-webhooks/saleor-async-webhook.ts | 50 +++++ .../saleor-webhooks/saleor-sync-webhook.ts | 38 ++++ .../saleor-webhooks/saleor-webhook.ts | 185 ++--------------- .../saleor-webhooks/saleor-async-webhook.ts | 14 +- .../saleor-webhooks/saleor-sync-webhook.ts | 14 +- .../saleor-webhooks/saleor-webhook.ts | 188 ++---------------- .../next/saleor-webhooks/saleor-webhook.ts | 178 ++--------------- src/handlers/shared/generic-saleor-webhook.ts | 30 +-- 8 files changed, 177 insertions(+), 520 deletions(-) diff --git a/src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-async-webhook.ts b/src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-async-webhook.ts index e69de29b..a567d1b5 100644 --- a/src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-async-webhook.ts +++ b/src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-async-webhook.ts @@ -0,0 +1,50 @@ +import { ASTNode } from "graphql"; + +import { AsyncWebhookEventType } from "@/types"; + +import { AWSLambdaHandler } from "../platform-adapter"; +import { SaleorWebApiWebhook, SaleorWebhookHandler, WebhookConfig } from "./saleor-webhook"; + +export class SaleorAsyncWebhook extends SaleorWebApiWebhook { + readonly event: AsyncWebhookEventType; + + protected readonly eventType = "async" as const; + + constructor( + /** + * Omit new required fields and make them optional. Validate in constructor. + * In 0.35.0 remove old fields + */ + configuration: Omit, "event" | "query"> & { + /** + * @deprecated - use `event` instead. Will be removed in 0.35.0 + */ + asyncEvent?: AsyncWebhookEventType; + event?: AsyncWebhookEventType; + query?: string | ASTNode; + } + ) { + if (!configuration.event && !configuration.asyncEvent) { + throw new Error("event or asyncEvent must be provided. asyncEvent is deprecated"); + } + + if (!configuration.query && !configuration.subscriptionQueryAst) { + throw new Error( + "query or subscriptionQueryAst must be provided. subscriptionQueryAst is deprecated" + ); + } + + super({ + ...configuration, + event: configuration.event! ?? configuration.asyncEvent!, + query: configuration.query! ?? configuration.subscriptionQueryAst!, + }); + + this.event = configuration.event! ?? configuration.asyncEvent!; + this.query = configuration.query! ?? configuration.subscriptionQueryAst!; + } + + createHandler(handlerFn: SaleorWebhookHandler): AWSLambdaHandler { + return super.createHandler(handlerFn); + } +} diff --git a/src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-sync-webhook.ts b/src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-sync-webhook.ts index e69de29b..ad43f8bd 100644 --- a/src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-sync-webhook.ts +++ b/src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-sync-webhook.ts @@ -0,0 +1,38 @@ +import { buildSyncWebhookResponsePayload } from "@/handlers/shared/sync-webhook-response-builder"; +import { SyncWebhookEventType } from "@/types"; + +import { AWSLambdaHandler } from "../platform-adapter"; +import { SaleorWebApiWebhook, SaleorWebhookHandler, WebhookConfig } from "./saleor-webhook"; + +type InjectedContext = { + buildResponse: typeof buildSyncWebhookResponsePayload; +}; +export class SaleorSyncWebhook< + TPayload = unknown, + TEvent extends SyncWebhookEventType = SyncWebhookEventType +> extends SaleorWebApiWebhook> { + readonly event: TEvent; + + protected readonly eventType = "sync" as const; + + protected extraContext = { + buildResponse: buildSyncWebhookResponsePayload, + }; + + constructor(configuration: WebhookConfig) { + super(configuration); + + this.event = configuration.event; + } + + createHandler( + handlerFn: SaleorWebhookHandler< + TPayload, + { + buildResponse: typeof buildSyncWebhookResponsePayload; + } + > + ): AWSLambdaHandler { + return super.createHandler(handlerFn); + } +} diff --git a/src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-webhook.ts b/src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-webhook.ts index 41b25cd4..5ee82909 100644 --- a/src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-webhook.ts +++ b/src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-webhook.ts @@ -1,195 +1,54 @@ -import { Context } from "aws-lambda"; -import { ASTNode } from "graphql"; +import { APIGatewayProxyResultV2, Context } from "aws-lambda"; -import { APL } from "@/APL"; import { createDebug } from "@/debug"; -import { gqlAstToString } from "@/gql-ast-to-string"; -import { WebhookContext, WebhookError } from "@/handlers/shared/process-saleor-webhook"; -import { WebhookErrorCodeMap } from "@/handlers/shared/saleor-webhook"; +import { + GenericSaleorWebhook, + GenericWebhookConfig, +} from "@/handlers/shared/generic-saleor-webhook"; +import { WebhookContext } from "@/handlers/shared/process-saleor-webhook"; import { SaleorWebhookValidator } from "@/handlers/shared/saleor-webhook-validator"; -import { AsyncWebhookEventType, SyncWebhookEventType, WebhookManifest } from "@/types"; +import { AsyncWebhookEventType, SyncWebhookEventType } from "@/types"; import { AwsLambdaAdapter, AWSLambdaHandler, AwsLambdaHandlerInput } from "../platform-adapter"; const debug = createDebug("SaleorWebhook"); -export interface WebhookConfig { - name?: string; - webhookPath: string; - event: Event; - isActive?: boolean; - apl: APL; - onError?(error: WebhookError | Error, event: AwsLambdaHandlerInput): void; - formatErrorResponse?( - error: WebhookError | Error, - event: AwsLambdaHandlerInput - ): Promise<{ - code: number; - body: string; - }>; - query: string | ASTNode; - /** - * @deprecated will be removed in 0.35.0, use query field instead - */ - subscriptionQueryAst?: ASTNode; -} +export type WebhookConfig = + GenericWebhookConfig; /** Function type provided by consumer in `SaleorWebApiWebhook.createHandler` */ export type SaleorWebhookHandler = ( event: AwsLambdaHandlerInput, context: Context, ctx: WebhookContext & TExtras -) => Response | Promise; +) => Promise | APIGatewayProxyResultV2; export abstract class SaleorWebApiWebhook< TPayload = unknown, TExtras extends Record = {} -> { - protected abstract eventType: "async" | "sync"; - - protected extraContext?: TExtras; - - name: string; - - webhookPath: string; - - query: string | ASTNode; - - event: AsyncWebhookEventType | SyncWebhookEventType; - - isActive?: boolean; - - apl: APL; - - onError: WebhookConfig["onError"]; - - formatErrorResponse: WebhookConfig["formatErrorResponse"]; - - protected constructor(configuration: WebhookConfig) { - const { - name, - webhookPath, - event, - query, - apl, - isActive = true, - subscriptionQueryAst, - } = configuration; - - this.name = name || `${event} webhook`; - /** - * Fallback subscriptionQueryAst to avoid breaking changes - * - * TODO Remove in 0.35.0 - */ - this.query = query ?? subscriptionQueryAst; - this.webhookPath = webhookPath; - this.event = event; - this.isActive = isActive; - this.apl = apl; - this.onError = configuration.onError; - this.formatErrorResponse = configuration.formatErrorResponse; - } - - private getTargetUrl(baseUrl: string) { - return new URL(this.webhookPath, baseUrl).href; - } - - /** - * Returns synchronous event manifest for this webhook. - * - * @param baseUrl Base URL used by your application - * @returns WebhookManifest - */ - getWebhookManifest(baseUrl: string): WebhookManifest { - const manifestBase: Omit = { - query: typeof this.query === "string" ? this.query : gqlAstToString(this.query), - name: this.name, - targetUrl: this.getTargetUrl(baseUrl), - isActive: this.isActive, - }; - - switch (this.eventType) { - case "async": - return { - ...manifestBase, - asyncEvents: [this.event as AsyncWebhookEventType], - }; - case "sync": - return { - ...manifestBase, - syncEvents: [this.event as SyncWebhookEventType], - }; - default: { - throw new Error("Class extended incorrectly"); - } - } - } - +> extends GenericSaleorWebhook { /** * Wraps provided function, to ensure incoming request comes from registered Saleor instance. * Also provides additional `context` object containing typed payload and request properties. */ createHandler(handlerFn: SaleorWebhookHandler): AWSLambdaHandler { return async (event, context) => { - debug(`Handler for webhook ${this.name} called`); const adapter = new AwsLambdaAdapter(event, context); - const webhookValidator = new SaleorWebhookValidator(adapter); - - const validationResult = await webhookValidator.validateRequest({ - allowedEvent: this.event, - apl: this.apl, + const validator = new SaleorWebhookValidator(adapter); + const prepareRequestResult = await super.prepareRequest({ + adapter, + validator, }); - if (validationResult.result === "ok") { - debug("Incoming request validated. Call handlerFn"); - - return handlerFn(event, context, { - ...(this.extraContext ?? ({} as TExtras)), - ...validationResult.context, - }); - } - - const { error } = validationResult; - - debug(`Unexpected error during processing the webhook ${this.name}`); - - if (error instanceof WebhookError) { - debug(`Validation error: ${error.message}`); - - if (this.onError) { - this.onError(error, event); - } - - if (this.formatErrorResponse) { - const { code, body } = await this.formatErrorResponse(error, event); - - return new Response(body, { status: code }); - } - - return new Response( - JSON.stringify({ - error: { - type: error.errorType, - message: error.message, - }, - }), - { status: WebhookErrorCodeMap[error.errorType] || 400 } - ); - } - debug("Unexpected error: %O", error); - - if (this.onError) { - this.onError(error, event); + if (prepareRequestResult.result === "sendResponse") { + return prepareRequestResult.response; } - if (this.formatErrorResponse) { - const { code, body } = await this.formatErrorResponse(error, event); - - return new Response(body, { status: code }); - } - - return new Response("Unexpected error while handling request", { status: 500 }); + debug("Incoming request validated. Call handlerFn"); + return handlerFn(event, context, { + ...(this.extraContext ?? ({} as TExtras)), + ...prepareRequestResult.context, + }); }; } } diff --git a/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-async-webhook.ts b/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-async-webhook.ts index f30217ee..8c7528d7 100644 --- a/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-async-webhook.ts +++ b/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-async-webhook.ts @@ -2,12 +2,8 @@ import { ASTNode } from "graphql"; import { AsyncWebhookEventType } from "@/types"; -import { - SaleorWebApiWebhook, - SaleorWebhookHandler, - WebApiRouteHandler, - WebhookConfig, -} from "./saleor-webhook"; +import { WebApiHandler } from "../platform-adapter"; +import { SaleorWebApiWebhook, SaleorWebhookHandler, WebhookConfig } from "./saleor-webhook"; export class SaleorAsyncWebhook extends SaleorWebApiWebhook { readonly event: AsyncWebhookEventType; @@ -26,7 +22,7 @@ export class SaleorAsyncWebhook extends SaleorWebApiWebhook< asyncEvent?: AsyncWebhookEventType; event?: AsyncWebhookEventType; query?: string | ASTNode; - }, + } ) { if (!configuration.event && !configuration.asyncEvent) { throw new Error("event or asyncEvent must be provided. asyncEvent is deprecated"); @@ -34,7 +30,7 @@ export class SaleorAsyncWebhook extends SaleorWebApiWebhook< if (!configuration.query && !configuration.subscriptionQueryAst) { throw new Error( - "query or subscriptionQueryAst must be provided. subscriptionQueryAst is deprecated", + "query or subscriptionQueryAst must be provided. subscriptionQueryAst is deprecated" ); } @@ -48,7 +44,7 @@ export class SaleorAsyncWebhook extends SaleorWebApiWebhook< this.query = configuration.query! ?? configuration.subscriptionQueryAst!; } - createHandler(handlerFn: SaleorWebhookHandler): WebApiRouteHandler { + createHandler(handlerFn: SaleorWebhookHandler): WebApiHandler { return super.createHandler(handlerFn); } } diff --git a/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-sync-webhook.ts b/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-sync-webhook.ts index 02bf5b67..d4b34909 100644 --- a/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-sync-webhook.ts +++ b/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-sync-webhook.ts @@ -1,19 +1,15 @@ import { buildSyncWebhookResponsePayload } from "@/handlers/shared/sync-webhook-response-builder"; import { SyncWebhookEventType } from "@/types"; -import { - SaleorWebApiWebhook, - SaleorWebhookHandler, - WebApiRouteHandler, - WebhookConfig, -} from "./saleor-webhook"; +import { WebApiHandler } from "../platform-adapter"; +import { SaleorWebApiWebhook, SaleorWebhookHandler, WebhookConfig } from "./saleor-webhook"; type InjectedContext = { buildResponse: typeof buildSyncWebhookResponsePayload; }; export class SaleorSyncWebhook< TPayload = unknown, - TEvent extends SyncWebhookEventType = SyncWebhookEventType, + TEvent extends SyncWebhookEventType = SyncWebhookEventType > extends SaleorWebApiWebhook> { readonly event: TEvent; @@ -35,8 +31,8 @@ export class SaleorSyncWebhook< { buildResponse: typeof buildSyncWebhookResponsePayload; } - >, - ): WebApiRouteHandler { + > + ): WebApiHandler { return super.createHandler(handlerFn); } } diff --git a/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-webhook.ts b/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-webhook.ts index ba2ce278..0c331399 100644 --- a/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-webhook.ts +++ b/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-webhook.ts @@ -1,37 +1,18 @@ -import { ASTNode } from "graphql"; - -import { APL } from "@/APL"; import { createDebug } from "@/debug"; -import { gqlAstToString } from "@/gql-ast-to-string"; -import { WebhookContext, WebhookError } from "@/handlers/shared/process-saleor-webhook"; -import { WebhookErrorCodeMap } from "@/handlers/shared/saleor-webhook"; +import { + GenericSaleorWebhook, + GenericWebhookConfig, +} from "@/handlers/shared/generic-saleor-webhook"; +import { WebhookContext } from "@/handlers/shared/process-saleor-webhook"; import { SaleorWebhookValidator } from "@/handlers/shared/saleor-webhook-validator"; -import { AsyncWebhookEventType, SyncWebhookEventType, WebhookManifest } from "@/types"; +import { AsyncWebhookEventType, SyncWebhookEventType } from "@/types"; -import { WebApiAdapter, WebApiHandler } from "../platform-adapter"; +import { WebApiAdapter, WebApiHandler, WebApiHandlerInput } from "../platform-adapter"; const debug = createDebug("SaleorWebhook"); -export interface WebhookConfig { - name?: string; - webhookPath: string; - event: Event; - isActive?: boolean; - apl: APL; - onError?(error: WebhookError | Error, request: Request): void; - formatErrorResponse?( - error: WebhookError | Error, - request: Request - ): Promise<{ - code: number; - body: string; - }>; - query: string | ASTNode; - /** - * @deprecated will be removed in 0.35.0, use query field instead - */ - subscriptionQueryAst?: ASTNode; -} +export type WebhookConfig = + GenericWebhookConfig; /** Function type provided by consumer in `SaleorWebApiWebhook.createHandler` */ export type SaleorWebhookHandler = ( @@ -42,152 +23,25 @@ export type SaleorWebhookHandler = ( export abstract class SaleorWebApiWebhook< TPayload = unknown, TExtras extends Record = {} -> { - protected abstract eventType: "async" | "sync"; - - protected extraContext?: TExtras; - - name: string; - - webhookPath: string; - - query: string | ASTNode; - - event: AsyncWebhookEventType | SyncWebhookEventType; - - isActive?: boolean; - - apl: APL; - - onError: WebhookConfig["onError"]; - - formatErrorResponse: WebhookConfig["formatErrorResponse"]; - - protected constructor(configuration: WebhookConfig) { - const { - name, - webhookPath, - event, - query, - apl, - isActive = true, - subscriptionQueryAst, - } = configuration; - - this.name = name || `${event} webhook`; - /** - * Fallback subscriptionQueryAst to avoid breaking changes - * - * TODO Remove in 0.35.0 - */ - this.query = query ?? subscriptionQueryAst; - this.webhookPath = webhookPath; - this.event = event; - this.isActive = isActive; - this.apl = apl; - this.onError = configuration.onError; - this.formatErrorResponse = configuration.formatErrorResponse; - } - - private getTargetUrl(baseUrl: string) { - return new URL(this.webhookPath, baseUrl).href; - } - - /** - * Returns synchronous event manifest for this webhook. - * - * @param baseUrl Base URL used by your application - * @returns WebhookManifest - */ - getWebhookManifest(baseUrl: string): WebhookManifest { - const manifestBase: Omit = { - query: typeof this.query === "string" ? this.query : gqlAstToString(this.query), - name: this.name, - targetUrl: this.getTargetUrl(baseUrl), - isActive: this.isActive, - }; - - switch (this.eventType) { - case "async": - return { - ...manifestBase, - asyncEvents: [this.event as AsyncWebhookEventType], - }; - case "sync": - return { - ...manifestBase, - syncEvents: [this.event as SyncWebhookEventType], - }; - default: { - throw new Error("Class extended incorrectly"); - } - } - } - - /** - * Wraps provided function, to ensure incoming request comes from registered Saleor instance. - * Also provides additional `context` object containing typed payload and request properties. - */ +> extends GenericSaleorWebhook { createHandler(handlerFn: SaleorWebhookHandler): WebApiHandler { return async (req) => { - debug(`Handler for webhook ${this.name} called`); const adapter = new WebApiAdapter(req); - const webhookValidator = new SaleorWebhookValidator(adapter); - - const validationResult = await webhookValidator.validateRequest({ - allowedEvent: this.event, - apl: this.apl, + const validator = new SaleorWebhookValidator(adapter); + const prepareRequestResult = await super.prepareRequest({ + adapter, + validator, }); - if (validationResult.result === "ok") { - debug("Incoming request validated. Call handlerFn"); - - return handlerFn(req, { - ...(this.extraContext ?? ({} as TExtras)), - ...validationResult.context, - }); + if (prepareRequestResult.result === "sendResponse") { + return prepareRequestResult.response; } - const { error } = validationResult; - - debug(`Unexpected error during processing the webhook ${this.name}`); - - if (error instanceof WebhookError) { - debug(`Validation error: ${error.message}`); - - if (this.onError) { - this.onError(error, req); - } - - if (this.formatErrorResponse) { - const { code, body } = await this.formatErrorResponse(error, req); - - return new Response(body, { status: code }); - } - - return new Response( - JSON.stringify({ - error: { - type: error.errorType, - message: error.message, - }, - }), - { status: WebhookErrorCodeMap[error.errorType] || 400 } - ); - } - debug("Unexpected error: %O", error); - - if (this.onError) { - this.onError(error, req); - } - - if (this.formatErrorResponse) { - const { code, body } = await this.formatErrorResponse(error, req); - - return new Response(body, { status: code }); - } - - return new Response("Unexpected error while handling request", { status: 500 }); + debug("Incoming request validated. Call handlerFn"); + return handlerFn(req, { + ...(this.extraContext ?? ({} as TExtras)), + ...prepareRequestResult.context, + }); }; } } diff --git a/src/handlers/platforms/next/saleor-webhooks/saleor-webhook.ts b/src/handlers/platforms/next/saleor-webhooks/saleor-webhook.ts index 5bd3e5c8..043d24ec 100644 --- a/src/handlers/platforms/next/saleor-webhooks/saleor-webhook.ts +++ b/src/handlers/platforms/next/saleor-webhooks/saleor-webhook.ts @@ -1,39 +1,20 @@ -import { ASTNode } from "graphql"; import { NextApiHandler, NextApiRequest, NextApiResponse } from "next"; -import { APL } from "@/APL"; import { createDebug } from "@/debug"; -import { gqlAstToString } from "@/gql-ast-to-string"; -import { WebhookContext, WebhookError } from "@/handlers/shared/process-saleor-webhook"; -import { WebhookErrorCodeMap } from "@/handlers/shared/saleor-webhook"; +import { + GenericSaleorWebhook, + GenericWebhookConfig, +} from "@/handlers/shared/generic-saleor-webhook"; +import { WebhookContext } from "@/handlers/shared/process-saleor-webhook"; import { SaleorWebhookValidator } from "@/handlers/shared/saleor-webhook-validator"; -import { AsyncWebhookEventType, SyncWebhookEventType, WebhookManifest } from "@/types"; +import { AsyncWebhookEventType, SyncWebhookEventType } from "@/types"; import { NextJsAdapter } from "../platform-adapter"; const debug = createDebug("SaleorWebhook"); -export interface WebhookConfig { - name?: string; - webhookPath: string; - event: Event; - isActive?: boolean; - apl: APL; - onError?(error: WebhookError | Error, req: NextApiRequest, res: NextApiResponse): void; - formatErrorResponse?( - error: WebhookError | Error, - req: NextApiRequest, - res: NextApiResponse - ): Promise<{ - code: number; - body: object | string; - }>; - query: string | ASTNode; - /** - * @deprecated will be removed in 0.35.0, use query field instead - */ - subscriptionQueryAst?: ASTNode; -} +export type WebhookConfig = + GenericWebhookConfig; export type NextWebhookApiHandler = ( req: NextApiRequest, @@ -44,88 +25,7 @@ export type NextWebhookApiHandler = ( export abstract class SaleorWebhook< TPayload = unknown, TExtras extends Record = {} -> { - protected abstract eventType: "async" | "sync"; - - protected extraContext?: TExtras; - - name: string; - - webhookPath: string; - - query: string | ASTNode; - - event: AsyncWebhookEventType | SyncWebhookEventType; - - isActive?: boolean; - - apl: APL; - - onError: WebhookConfig["onError"]; - - formatErrorResponse: WebhookConfig["formatErrorResponse"]; - - protected constructor(configuration: WebhookConfig) { - const { - name, - webhookPath, - event, - query, - apl, - isActive = true, - subscriptionQueryAst, - } = configuration; - - this.name = name || `${event} webhook`; - /** - * Fallback subscriptionQueryAst to avoid breaking changes - * - * TODO Remove in 0.35.0 - */ - this.query = query ?? subscriptionQueryAst; - this.webhookPath = webhookPath; - this.event = event; - this.isActive = isActive; - this.apl = apl; - this.onError = configuration.onError; - this.formatErrorResponse = configuration.formatErrorResponse; - } - - private getTargetUrl(baseUrl: string) { - return new URL(this.webhookPath, baseUrl).href; - } - - /** - * Returns synchronous event manifest for this webhook. - * - * @param baseUrl Base URL used by your application - * @returns WebhookManifest - */ - getWebhookManifest(baseUrl: string): WebhookManifest { - const manifestBase: Omit = { - query: typeof this.query === "string" ? this.query : gqlAstToString(this.query), - name: this.name, - targetUrl: this.getTargetUrl(baseUrl), - isActive: this.isActive, - }; - - switch (this.eventType) { - case "async": - return { - ...manifestBase, - asyncEvents: [this.event as AsyncWebhookEventType], - }; - case "sync": - return { - ...manifestBase, - syncEvents: [this.event as SyncWebhookEventType], - }; - default: { - throw new Error("Class extended incorrectly"); - } - } - } - +> extends GenericSaleorWebhook { /** * Wraps provided function, to ensure incoming request comes from registered Saleor instance. * Also provides additional `context` object containing typed payload and request properties. @@ -133,59 +33,21 @@ export abstract class SaleorWebhook< createHandler(handlerFn: NextWebhookApiHandler): NextApiHandler { return async (req, res) => { const adapter = new NextJsAdapter(req, res); - const webhookValidator = new SaleorWebhookValidator(adapter); - - debug(`Handler for webhook ${this.name} called`); - const validationResult = await webhookValidator.validateRequest({ - allowedEvent: this.event, - apl: this.apl, + const validator = new SaleorWebhookValidator(adapter); + const prepareRequestResult = await super.prepareRequest({ + adapter, + validator, }); - if (validationResult.result === "ok") { - debug("Incoming request validated. Call handlerFn"); - - return handlerFn(req, res, { - ...(this.extraContext ?? ({} as TExtras)), - ...validationResult.context, - }); - } - - debug(`Unexpected error during processing the webhook ${this.name}`); - const e = validationResult.error; - - if (e instanceof WebhookError) { - debug(`Validation error: ${e.message}`); - - if (this.onError) { - this.onError(e, req, res); - } - - if (this.formatErrorResponse) { - const { code, body } = await this.formatErrorResponse(e, req, res); - - return res.status(code).send(body); - } - - return res.status(WebhookErrorCodeMap[e.errorType] || 400).send({ - error: { - type: e.errorType, - message: e.message, - }, - }); - } - debug("Unexpected error: %O", e); - - if (this.onError) { - this.onError(e, req, res); + if (prepareRequestResult.result === "sendResponse") { + return prepareRequestResult.response; } - if (this.formatErrorResponse) { - const { code, body } = await this.formatErrorResponse(e, req, res); - - return res.status(code).send(body); - } - - return res.status(500).end(); + debug("Incoming request validated. Call handlerFn"); + return handlerFn(req, res, { + ...(this.extraContext ?? ({} as TExtras)), + ...prepareRequestResult.context, + }); }; } } diff --git a/src/handlers/shared/generic-saleor-webhook.ts b/src/handlers/shared/generic-saleor-webhook.ts index 76b7ba6e..bebcb4de 100644 --- a/src/handlers/shared/generic-saleor-webhook.ts +++ b/src/handlers/shared/generic-saleor-webhook.ts @@ -11,7 +11,10 @@ import { AsyncWebhookEventType, SyncWebhookEventType, WebhookManifest } from "@/ const debug = createDebug("SaleorWebhook"); -export interface WebhookConfig { +export interface GenericWebhookConfig< + RequestType, + Event = AsyncWebhookEventType | SyncWebhookEventType +> { name?: string; webhookPath: string; event: Event; @@ -32,7 +35,7 @@ export interface WebhookConfig = {} @@ -53,11 +56,11 @@ export abstract class GenericSaleorWebApiWebhook< apl: APL; - onError: WebhookConfig["onError"]; + onError: GenericWebhookConfig["onError"]; - formatErrorResponse: WebhookConfig["formatErrorResponse"]; + formatErrorResponse: GenericWebhookConfig["formatErrorResponse"]; - protected constructor(configuration: WebhookConfig) { + protected constructor(configuration: GenericWebhookConfig) { const { name, webhookPath, @@ -118,16 +121,15 @@ export abstract class GenericSaleorWebApiWebhook< } } - protected async prepareRequest>({ + protected async prepareRequest>({ adapter, validator, }: { - adapter: A; - validator: SaleorWebhookValidator; - callback: (adapter: A, context: WebhookContext) => unknown; + adapter: Adapter; + validator: SaleorWebhookValidator; }): Promise< | { result: "callHandler"; context: WebhookContext } - | { result: "sendResponse"; response: unknown } + | { result: "sendResponse"; response: ReturnType } > { const validationResult = await validator.validateRequest({ allowedEvent: this.event, @@ -158,7 +160,7 @@ export abstract class GenericSaleorWebApiWebhook< status: code, body, bodyType: "string", - }), + }) as ReturnType, }; } @@ -173,7 +175,7 @@ export abstract class GenericSaleorWebApiWebhook< }, }, status: WebhookErrorCodeMap[error.errorType] || 400, - }), + }) as ReturnType, }; } debug("Unexpected error: %O", error); @@ -191,7 +193,7 @@ export abstract class GenericSaleorWebApiWebhook< status: code, body, bodyType: "string", - }), + }) as ReturnType, }; } @@ -201,7 +203,7 @@ export abstract class GenericSaleorWebApiWebhook< status: 500, body: "Unexpected error while handling request", bodyType: "string", - }), + }) as ReturnType, }; } } From dd575a1f19c1262cc6107a8ba0bae9ffcf049fd6 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 24 Jan 2025 12:40:13 +0100 Subject: [PATCH 53/58] Remove unused file --- src/handlers/webhooks/abstract-webhook.ts | 301 ---------------------- 1 file changed, 301 deletions(-) delete mode 100644 src/handlers/webhooks/abstract-webhook.ts diff --git a/src/handlers/webhooks/abstract-webhook.ts b/src/handlers/webhooks/abstract-webhook.ts deleted file mode 100644 index 76ac1649..00000000 --- a/src/handlers/webhooks/abstract-webhook.ts +++ /dev/null @@ -1,301 +0,0 @@ -import { SpanKind, SpanStatusCode } from "@opentelemetry/api"; -import { ASTNode } from "graphql"; -import { NextApiRequest, NextApiResponse } from "next"; - -import { APL } from "@/APL"; -import { createDebug } from "@/debug"; -import { fetchRemoteJwks } from "@/fetch-remote-jwks"; -import { gqlAstToString } from "@/gql-ast-to-string"; -import { WebhookContext, WebhookError } from "@/handlers/shared/process-saleor-webhook"; -import { WebhookErrorCodeMap } from "@/handlers/shared/saleor-webhook"; -import { getOtelTracer } from "@/open-telemetry"; -import { AsyncWebhookEventType, SyncWebhookEventType, WebhookManifest } from "@/types"; -import { parseSchemaVersion } from "@/util"; -import { verifySignatureWithJwks } from "@/verify-signature"; - -import { ActionHandlerResult, PlatformAdapterInterface, PlatformAdapterMiddleware } from "../shared"; - -const debug = createDebug("SaleorWebhook"); - -export interface WebhookConfig { - name?: string; - webhookPath: string; - event: Event; - isActive?: boolean; - apl: APL; - onError?(error: WebhookError | Error, req: NextApiRequest, res: NextApiResponse): void; - formatErrorResponse?( - error: WebhookError | Error, - req: NextApiRequest, - res: NextApiResponse - ): Promise<{ - code: number; - body: object | string; - }>; - query: string | ASTNode; - /** - * @deprecated will be removed in 0.35.0, use query field instead - */ - subscriptionQueryAst?: ASTNode; -} - -export type NextWebhookApiHandler = ( - req: NextApiRequest, - res: NextApiResponse, - ctx: WebhookContext & TExtras -) => unknown | Promise; - -export abstract class SaleorWebhook< - Fn, - Request -> { - name: string; - - webhookPath: string; - - query: string | ASTNode; - - event: AsyncWebhookEventType | SyncWebhookEventType; - - isActive?: boolean; - - apl: APL; - - onError: WebhookConfig["onError"]; - - formatErrorResponse: WebhookConfig["formatErrorResponse"]; - - protected constructor(configuration: WebhookConfig, protected adapter: PlatformAdapterInterface, protected adapterMiddleware: PlatformAdapterMiddleware) { - const { - name, - webhookPath, - event, - query, - apl, - isActive = true, - subscriptionQueryAst, - } = configuration; - - this.name = name || `${event} webhook`; - /** - * Fallback subscriptionQueryAst to avoid breaking changes - * - * TODO Remove in 0.35.0 - */ - this.query = query ?? subscriptionQueryAst; - this.webhookPath = webhookPath; - this.event = event; - this.isActive = isActive; - this.apl = apl; - this.onError = configuration.onError; - this.formatErrorResponse = configuration.formatErrorResponse; - } - - private getTargetUrl(baseUrl: string) { - return new URL(this.webhookPath, baseUrl).href; - } - - /** - * Returns synchronous event manifest for this webhook. - * - * @param baseUrl Base URL used by your application - * @returns WebhookManifest - */ - protected getWebhookManifestBase(baseUrl: string): WebhookManifest { - return { - query: typeof this.query === "string" ? this.query : gqlAstToString(this.query), - name: this.name, - targetUrl: this.getTargetUrl(baseUrl), - isActive: this.isActive, - }; - } - - abstract getWebhookManifest(baseUrl: string): WebhookManifest; - - abstract createHandler(handlerFn: Fn): Fn; - - protected processWebhookRequest({ allowedEvent }: { allowedEvent: string }): Promise> { - const tracer = getOtelTracer(); - - return tracer.startActiveSpan( - "processSaleorWebhook", - { - kind: SpanKind.INTERNAL, - attributes: { - allowedEvent, - }, - }, - async (span) => { - try { - debug("Request processing started"); - - if (this.adapter.method !== "POST") { - debug("Wrong HTTP method"); - throw new WebhookError("Wrong request method, only POST allowed", "WRONG_METHOD"); - } - - const { event, signature, saleorApiUrl } = this.adapterMiddleware.getSaleorHeaders(); - const baseUrl = this.adapter.getBaseUrl(); - - if (!baseUrl) { - debug("Missing host header"); - throw new WebhookError("Missing host header", "MISSING_HOST_HEADER"); - } - - if (!saleorApiUrl) { - debug("Missing saleor-api-url header"); - throw new WebhookError("Missing saleor-api-url header", "MISSING_API_URL_HEADER"); - } - - if (!event) { - debug("Missing saleor-event header"); - throw new WebhookError("Missing saleor-event header", "MISSING_EVENT_HEADER"); - } - - const expected = allowedEvent.toLowerCase(); - - if (event !== expected) { - debug(`Wrong incoming request event: ${event}. Expected: ${expected}`); - - throw new WebhookError( - `Wrong incoming request event: ${event}. Expected: ${expected}`, - "WRONG_EVENT" - ); - } - - if (!signature) { - debug("No signature"); - - throw new WebhookError("Missing saleor-signature header", "MISSING_SIGNATURE_HEADER"); - } - - const rawBody = await this.adapter.getRawBody(); - - if (!rawBody) { - debug("Missing request body"); - - throw new WebhookError("Missing request body", "MISSING_REQUEST_BODY"); - } - - let parsedBody: unknown & { version?: string | null }; - - try { - parsedBody = JSON.parse(rawBody); - } catch { - debug("Request body cannot be parsed"); - - throw new WebhookError("Request body can't be parsed", "CANT_BE_PARSED"); - } - - let parsedSchemaVersion: number | null = null; - - try { - parsedSchemaVersion = parseSchemaVersion(parsedBody.version); - } catch { - debug("Schema version cannot be parsed"); - } - - /** - * Verify if the app is properly installed for given Saleor API URL - */ - const authData = await this.apl.get(saleorApiUrl); - - if (!authData) { - debug("APL didn't found auth data for %s", saleorApiUrl); - - throw new WebhookError( - `Can't find auth data for ${saleorApiUrl}. Please register the application`, - "NOT_REGISTERED" - ); - } - - /** - * Verify payload signature - * - * TODO: Add test for repeat verification scenario - */ - try { - debug("Will verify signature with JWKS saved in AuthData"); - - if (!authData.jwks) { - throw new Error("JWKS not found in AuthData"); - } - - await verifySignatureWithJwks(authData.jwks, signature, rawBody); - } catch { - debug("Request signature check failed. Refresh the JWKS cache and check again"); - - const newJwks = await fetchRemoteJwks(authData.saleorApiUrl).catch((e) => { - debug(e); - - throw new WebhookError("Fetching remote JWKS failed", "SIGNATURE_VERIFICATION_FAILED"); - }); - - debug("Fetched refreshed JWKS"); - - try { - debug("Second attempt to validate the signature JWKS, using fresh tokens from the API"); - - await verifySignatureWithJwks(newJwks, signature, rawBody); - - debug("Verification successful - update JWKS in the AuthData"); - - await this.apl.set({ ...authData, jwks: newJwks }); - } catch { - debug("Second attempt also ended with validation error. Reject the webhook"); - - throw new WebhookError( - "Request signature check failed", - "SIGNATURE_VERIFICATION_FAILED" - ); - } - } - - span.setStatus({ - code: SpanStatusCode.OK, - }); - - return { - baseUrl, - event, - payload: parsedBody as T, - authData, - schemaVersion: parsedSchemaVersion, - }; - } catch (err) { - const message = (err as Error)?.message ?? "Unknown error"; - - span.setStatus({ - code: SpanStatusCode.ERROR, - message, - }); - - throw err; - } finally { - span.end(); - } - } - ); - } - - protected getDefaultErrorResponse(error: WebhookError | Error): ActionHandlerResult { - if (error instanceof WebhookError) { - const status = WebhookErrorCodeMap[error.errorType] || 400; - return { - body: { - type: error.errorType, - message: error.message - }, - status, - bodyType: "json" - }; - } - - return { - body: "Unexpected server error", - bodyType: "string", - status: 500 - } - }; - -} From f7b1aec725f765559da428b20dc3447c51550a14 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 24 Jan 2025 12:43:16 +0100 Subject: [PATCH 54/58] Fix TS error --- src/handlers/shared/generic-adapter-use-case-types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/handlers/shared/generic-adapter-use-case-types.ts b/src/handlers/shared/generic-adapter-use-case-types.ts index e2a4d378..013fe526 100644 --- a/src/handlers/shared/generic-adapter-use-case-types.ts +++ b/src/handlers/shared/generic-adapter-use-case-types.ts @@ -11,7 +11,7 @@ export type HTTPMethod = typeof HTTPMethod[keyof typeof HTTPMethod]; /** Status code of the result, for most platforms it's mapped to HTTP status code * however when request is not HTTP it can be mapped to something else */ -export type ResultStatusCodes = 200 | 201 | 400 | 401 | 403 | 404 | 405 | 500 | 503; +export type ResultStatusCodes = number; /** Shape of result that should be returned from use case * that is then translated by adapter to a valid platform response */ From f9e0d3f96d06028f4ce741e5e6969eff4fe7aafa Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 24 Jan 2025 15:07:42 +0100 Subject: [PATCH 55/58] Change webhook validator to not require adapter in constructor for easier testing --- .../saleor-webhooks/saleor-webhook.ts | 7 +--- .../saleor-webhooks/saleor-webhook.ts | 7 +--- .../next/saleor-webhooks/saleor-webhook.ts | 7 +--- src/handlers/shared/generic-saleor-webhook.ts | 29 +++++++------- src/handlers/shared/process-saleor-webhook.ts | 4 +- .../shared/saleor-webhook-validator.ts | 39 +++++++++---------- 6 files changed, 40 insertions(+), 53 deletions(-) diff --git a/src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-webhook.ts b/src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-webhook.ts index 5ee82909..2829d8d6 100644 --- a/src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-webhook.ts +++ b/src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-webhook.ts @@ -6,7 +6,6 @@ import { GenericWebhookConfig, } from "@/handlers/shared/generic-saleor-webhook"; import { WebhookContext } from "@/handlers/shared/process-saleor-webhook"; -import { SaleorWebhookValidator } from "@/handlers/shared/saleor-webhook-validator"; import { AsyncWebhookEventType, SyncWebhookEventType } from "@/types"; import { AwsLambdaAdapter, AWSLambdaHandler, AwsLambdaHandlerInput } from "../platform-adapter"; @@ -34,11 +33,7 @@ export abstract class SaleorWebApiWebhook< createHandler(handlerFn: SaleorWebhookHandler): AWSLambdaHandler { return async (event, context) => { const adapter = new AwsLambdaAdapter(event, context); - const validator = new SaleorWebhookValidator(adapter); - const prepareRequestResult = await super.prepareRequest({ - adapter, - validator, - }); + const prepareRequestResult = await super.prepareRequest(adapter); if (prepareRequestResult.result === "sendResponse") { return prepareRequestResult.response; diff --git a/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-webhook.ts b/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-webhook.ts index 0c331399..ae32ebbe 100644 --- a/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-webhook.ts +++ b/src/handlers/platforms/fetch-api/saleor-webhooks/saleor-webhook.ts @@ -4,7 +4,6 @@ import { GenericWebhookConfig, } from "@/handlers/shared/generic-saleor-webhook"; import { WebhookContext } from "@/handlers/shared/process-saleor-webhook"; -import { SaleorWebhookValidator } from "@/handlers/shared/saleor-webhook-validator"; import { AsyncWebhookEventType, SyncWebhookEventType } from "@/types"; import { WebApiAdapter, WebApiHandler, WebApiHandlerInput } from "../platform-adapter"; @@ -27,11 +26,7 @@ export abstract class SaleorWebApiWebhook< createHandler(handlerFn: SaleorWebhookHandler): WebApiHandler { return async (req) => { const adapter = new WebApiAdapter(req); - const validator = new SaleorWebhookValidator(adapter); - const prepareRequestResult = await super.prepareRequest({ - adapter, - validator, - }); + const prepareRequestResult = await super.prepareRequest(adapter); if (prepareRequestResult.result === "sendResponse") { return prepareRequestResult.response; diff --git a/src/handlers/platforms/next/saleor-webhooks/saleor-webhook.ts b/src/handlers/platforms/next/saleor-webhooks/saleor-webhook.ts index 043d24ec..17fe36f6 100644 --- a/src/handlers/platforms/next/saleor-webhooks/saleor-webhook.ts +++ b/src/handlers/platforms/next/saleor-webhooks/saleor-webhook.ts @@ -6,7 +6,6 @@ import { GenericWebhookConfig, } from "@/handlers/shared/generic-saleor-webhook"; import { WebhookContext } from "@/handlers/shared/process-saleor-webhook"; -import { SaleorWebhookValidator } from "@/handlers/shared/saleor-webhook-validator"; import { AsyncWebhookEventType, SyncWebhookEventType } from "@/types"; import { NextJsAdapter } from "../platform-adapter"; @@ -33,11 +32,7 @@ export abstract class SaleorWebhook< createHandler(handlerFn: NextWebhookApiHandler): NextApiHandler { return async (req, res) => { const adapter = new NextJsAdapter(req, res); - const validator = new SaleorWebhookValidator(adapter); - const prepareRequestResult = await super.prepareRequest({ - adapter, - validator, - }); + const prepareRequestResult = await super.prepareRequest(adapter); if (prepareRequestResult.result === "sendResponse") { return prepareRequestResult.response; diff --git a/src/handlers/shared/generic-saleor-webhook.ts b/src/handlers/shared/generic-saleor-webhook.ts index bebcb4de..b3db8f73 100644 --- a/src/handlers/shared/generic-saleor-webhook.ts +++ b/src/handlers/shared/generic-saleor-webhook.ts @@ -3,7 +3,7 @@ import { ASTNode } from "graphql"; import { APL } from "@/APL"; import { createDebug } from "@/debug"; import { gqlAstToString } from "@/gql-ast-to-string"; -import { PlatformAdapterInterface } from "@/handlers/shared"; +import { PlatformAdapterInterface, PlatformAdapterMiddleware } from "@/handlers/shared"; import { WebhookContext, WebhookError } from "@/handlers/shared/process-saleor-webhook"; import { WebhookErrorCodeMap } from "@/handlers/shared/saleor-webhook"; import { SaleorWebhookValidator } from "@/handlers/shared/saleor-webhook-validator"; @@ -36,10 +36,12 @@ export interface GenericWebhookConfig< } export abstract class GenericSaleorWebhook< - RequestType, + TRequestType, TPayload = unknown, TExtras extends Record = {} > { + private webhookValidator = new SaleorWebhookValidator(); + protected abstract eventType: "async" | "sync"; protected extraContext?: TExtras; @@ -56,11 +58,11 @@ export abstract class GenericSaleorWebhook< apl: APL; - onError: GenericWebhookConfig["onError"]; + onError: GenericWebhookConfig["onError"]; - formatErrorResponse: GenericWebhookConfig["formatErrorResponse"]; + formatErrorResponse: GenericWebhookConfig["formatErrorResponse"]; - protected constructor(configuration: GenericWebhookConfig) { + protected constructor(configuration: GenericWebhookConfig) { const { name, webhookPath, @@ -121,19 +123,18 @@ export abstract class GenericSaleorWebhook< } } - protected async prepareRequest>({ - adapter, - validator, - }: { - adapter: Adapter; - validator: SaleorWebhookValidator; - }): Promise< + protected async prepareRequest>( + adapter: Adapter + ): Promise< | { result: "callHandler"; context: WebhookContext } | { result: "sendResponse"; response: ReturnType } > { - const validationResult = await validator.validateRequest({ + const adapterMiddleware = new PlatformAdapterMiddleware(adapter); + const validationResult = await this.webhookValidator.validateRequest({ allowedEvent: this.event, apl: this.apl, + adapter, + adapterMiddleware, }); if (validationResult.result === "ok") { @@ -206,4 +207,6 @@ export abstract class GenericSaleorWebhook< }) as ReturnType, }; } + + abstract createHandler(handlerFn: unknown): unknown; } diff --git a/src/handlers/shared/process-saleor-webhook.ts b/src/handlers/shared/process-saleor-webhook.ts index ba36e913..326dbb49 100644 --- a/src/handlers/shared/process-saleor-webhook.ts +++ b/src/handlers/shared/process-saleor-webhook.ts @@ -28,10 +28,10 @@ export class WebhookError extends Error { } } -export type WebhookContext = { +export type WebhookContext = { baseUrl: string; event: string; - payload: T; + payload: TPayload; authData: AuthData; /** For Saleor < 3.15 it will be null. */ schemaVersion: number | null; diff --git a/src/handlers/shared/saleor-webhook-validator.ts b/src/handlers/shared/saleor-webhook-validator.ts index c5e03ccb..a2ef6119 100644 --- a/src/handlers/shared/saleor-webhook-validator.ts +++ b/src/handlers/shared/saleor-webhook-validator.ts @@ -11,28 +11,23 @@ import { PlatformAdapterMiddleware } from "./adapter-middleware"; import { PlatformAdapterInterface } from "./generic-adapter-use-case-types"; import { WebhookContext, WebhookError } from "./process-saleor-webhook"; -type WebhookValidationResult = - | { result: "ok"; context: WebhookContext } +type WebhookValidationResult = + | { result: "ok"; context: WebhookContext } | { result: "failure"; error: WebhookError }; -export class SaleorWebhookValidator { +export class SaleorWebhookValidator { private debug = createDebug("processProtectedHandler"); private tracer = getOtelTracer(); - constructor(private adapter: PlatformAdapterInterface) {} - - private adapterMiddleware = new PlatformAdapterMiddleware(this.adapter); - - async validateRequest({ - allowedEvent, - apl, - }: { + async validateRequest(config: { allowedEvent: string; apl: APL; - }): Promise> { + adapter: PlatformAdapterInterface; + adapterMiddleware: PlatformAdapterMiddleware; + }): Promise> { try { - const context = await this.validateRequestOrThrowError({ allowedEvent, apl }); + const context = await this.validateRequestOrThrowError(config); return { result: "ok", @@ -46,13 +41,17 @@ export class SaleorWebhookValidator { } } - private async validateRequestOrThrowError({ + private async validateRequestOrThrowError({ allowedEvent, apl, + adapter, + adapterMiddleware, }: { allowedEvent: string; apl: APL; - }): Promise> { + adapter: PlatformAdapterInterface; + adapterMiddleware: PlatformAdapterMiddleware; + }): Promise> { return this.tracer.startActiveSpan( "processSaleorWebhook", { @@ -65,13 +64,13 @@ export class SaleorWebhookValidator { try { this.debug("Request processing started"); - if (this.adapter.method !== "POST") { + if (adapter.method !== "POST") { this.debug("Wrong HTTP method"); throw new WebhookError("Wrong request method, only POST allowed", "WRONG_METHOD"); } - const { event, signature, saleorApiUrl } = this.adapterMiddleware.getSaleorHeaders(); - const baseUrl = this.adapter.getBaseUrl(); + const { event, signature, saleorApiUrl } = adapterMiddleware.getSaleorHeaders(); + const baseUrl = adapter.getBaseUrl(); if (!baseUrl) { this.debug("Missing host header"); @@ -105,7 +104,7 @@ export class SaleorWebhookValidator { throw new WebhookError("Missing saleor-signature header", "MISSING_SIGNATURE_HEADER"); } - const rawBody = await this.adapter.getRawBody(); + const rawBody = await adapter.getRawBody(); if (!rawBody) { this.debug("Missing request body"); @@ -198,7 +197,7 @@ export class SaleorWebhookValidator { return { baseUrl, event, - payload: parsedBody as T, + payload: parsedBody as TPayload, authData, schemaVersion: parsedSchemaVersion, }; From 3d09ac3e2625ca98f847e9215b4a71d89e4aee08 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 24 Jan 2025 15:08:18 +0100 Subject: [PATCH 56/58] Fix tests --- .../saleor-async-webhook.test.ts | 51 ++++++++----------- .../saleor-sync-webhook.test.ts | 33 ++++++------ 2 files changed, 39 insertions(+), 45 deletions(-) diff --git a/src/handlers/platforms/next/saleor-webhooks/saleor-async-webhook.test.ts b/src/handlers/platforms/next/saleor-webhooks/saleor-async-webhook.test.ts index cf5c716a..7b7136f6 100644 --- a/src/handlers/platforms/next/saleor-webhooks/saleor-async-webhook.test.ts +++ b/src/handlers/platforms/next/saleor-webhooks/saleor-async-webhook.test.ts @@ -2,17 +2,18 @@ import { ASTNode } from "graphql"; import { createMocks } from "node-mocks-http"; import { afterEach, describe, expect, it, vi } from "vitest"; +import { WebhookError } from "@/handlers/shared/process-saleor-webhook"; +import { SaleorWebhookValidator } from "@/handlers/shared/saleor-webhook-validator"; import { MockAPL } from "@/test-utils/mock-apl"; import { AsyncWebhookEventType } from "@/types"; -import { processSaleorWebhook } from "./process-saleor-webhook"; import { SaleorAsyncWebhook } from "./saleor-async-webhook"; import { NextWebhookApiHandler, WebhookConfig } from "./saleor-webhook"; const webhookPath = "api/webhooks/product-updated"; const baseUrl = "http://example.com"; -describe("SaleorAsyncWebhook", () => { +describe("Next.js SaleorAsyncWebhook", () => { const mockAPL = new MockAPL(); afterEach(async () => { @@ -57,22 +58,22 @@ describe("SaleorAsyncWebhook", () => { }); it("Test createHandler which return success", async () => { - // prepare mocked context returned by mocked process function - vi.mock("./process-saleor-webhook"); - - vi.mocked(processSaleorWebhook).mockImplementationOnce(async () => ({ - baseUrl: "example.com", - event: "product_updated", - payload: { data: "test_payload" }, - schemaVersion: 3.19, - authData: { - domain: "example.com", - token: "token", - jwks: "", - saleorApiUrl: "https://example.com/graphql/", - appId: "12345", + vi.spyOn(SaleorWebhookValidator.prototype, "validateRequest").mockResolvedValue({ + result: "ok", + context: { + baseUrl: "example.com", + event: "product_updated", + payload: { data: "test_payload" }, + schemaVersion: 3.19, + authData: { + domain: "example.com", + token: "token", + jwks: "", + saleorApiUrl: "https://example.com/graphql/", + appId: "12345", + }, }, - })); + }); // Test handler - will throw error if mocked context is not passed to it // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -109,16 +110,9 @@ describe("SaleorAsyncWebhook", () => { }); // prepare mocked context returned by mocked process function - vi.mock("./process-saleor-webhook"); - - vi.mocked(processSaleorWebhook).mockImplementationOnce(async () => { - /** - * This mock should throw WebhookError, but there was TypeError related to constructor of extended class. - * Try "throw new WebhookError()" to check it. - * - * For test suite it doesn't matter, because errors thrown from source code are valid - */ - throw new Error("Test error message"); + vi.spyOn(SaleorWebhookValidator.prototype, "validateRequest").mockResolvedValue({ + result: "failure", + error: new WebhookError("Test error message", "OTHER"), }); // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -144,8 +138,7 @@ describe("SaleorAsyncWebhook", () => { expect.objectContaining({ message: "Test error message", }), - req, - res + req ); /** diff --git a/src/handlers/platforms/next/saleor-webhooks/saleor-sync-webhook.test.ts b/src/handlers/platforms/next/saleor-webhooks/saleor-sync-webhook.test.ts index c03c8dd3..7e011683 100644 --- a/src/handlers/platforms/next/saleor-webhooks/saleor-sync-webhook.test.ts +++ b/src/handlers/platforms/next/saleor-webhooks/saleor-sync-webhook.test.ts @@ -1,30 +1,31 @@ import { createMocks } from "node-mocks-http"; import { describe, expect, it, vi } from "vitest"; +import { SaleorWebhookValidator } from "@/handlers/shared/saleor-webhook-validator"; import { MockAPL } from "@/test-utils/mock-apl"; -import { processSaleorWebhook } from "./process-saleor-webhook"; import { SaleorSyncWebhook } from "./saleor-sync-webhook"; -describe("SaleorSyncWebhook", () => { +describe("Next.js SaleorSyncWebhook", () => { const mockApl = new MockAPL(); it("Provides type-safe response builder in the context", async () => { - vi.mock("./process-saleor-webhook"); - - vi.mocked(processSaleorWebhook).mockImplementationOnce(async () => ({ - baseUrl: "example.com", - event: "CHECKOUT_CALCULATE_TAXES", - payload: { data: "test_payload" }, - schemaVersion: 3.19, - authData: { - domain: mockApl.workingSaleorDomain, - token: mockApl.mockToken, - jwks: mockApl.mockJwks, - saleorApiUrl: mockApl.workingSaleorApiUrl, - appId: mockApl.mockAppId, + vi.spyOn(SaleorWebhookValidator.prototype, "validateRequest").mockResolvedValue({ + result: "ok", + context: { + baseUrl: "example.com", + event: "CHECKOUT_CALCULATE_TAXES", + payload: { data: "test_payload" }, + schemaVersion: 3.19, + authData: { + domain: mockApl.workingSaleorDomain, + token: mockApl.mockToken, + jwks: mockApl.mockJwks, + saleorApiUrl: mockApl.workingSaleorApiUrl, + appId: mockApl.mockAppId, + }, }, - })); + }); const { req, res } = createMocks({ method: "POST", From 671204013c3b2a0bcc574c0319de45f02c25a5b4 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Fri, 24 Jan 2025 15:34:12 +0100 Subject: [PATCH 57/58] Add tests for request validator --- .../shared/saleor-webhook-validator.test.ts | 260 ++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 src/handlers/shared/saleor-webhook-validator.test.ts diff --git a/src/handlers/shared/saleor-webhook-validator.test.ts b/src/handlers/shared/saleor-webhook-validator.test.ts new file mode 100644 index 00000000..22044585 --- /dev/null +++ b/src/handlers/shared/saleor-webhook-validator.test.ts @@ -0,0 +1,260 @@ +/* eslint-disable max-classes-per-file */ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +import { MockAPL } from "@/test-utils/mock-apl"; +import * as verifySignatureModule from "@/verify-signature"; + +import { PlatformAdapterMiddleware } from "./adapter-middleware"; +import { HTTPMethod, PlatformAdapterInterface } from "./generic-adapter-use-case-types"; +import { SaleorWebhookValidator } from "./saleor-webhook-validator"; + +vi.spyOn(verifySignatureModule, "verifySignatureFromApiUrl").mockImplementation( + async (domain, signature) => { + if (signature !== "mocked_signature") { + throw new Error("Wrong signature"); + } + } +); +vi.spyOn(verifySignatureModule, "verifySignatureWithJwks").mockImplementation( + async (domain, signature) => { + if (signature !== "mocked_signature") { + throw new Error("Wrong signature"); + } + } +); + +class MockAdapter implements PlatformAdapterInterface { + send() { + throw new Error("Method not implemented."); + } + + getHeader() { + return null; + } + + async getBody() { + return null; + } + + async getRawBody() { + return "{}"; + } + + getBaseUrl() { + return ""; + } + + method: HTTPMethod = "POST"; + + request = {}; +} + +describe("SaleorWebhookValidator", () => { + const mockAPL = new MockAPL(); + const validator = new SaleorWebhookValidator(); + let adapter: MockAdapter; + let middleware: PlatformAdapterMiddleware; + + const validHeaders = { + saleorApiUrl: mockAPL.workingSaleorApiUrl, + event: "product_updated", + schemaVersion: 3.2, + signature: "mocked_signature", + authorizationBearer: "mocked_bearer", + domain: "example.com", + }; + + beforeEach(() => { + adapter = new MockAdapter(); + middleware = new PlatformAdapterMiddleware(adapter); + vi.spyOn(adapter, "getBaseUrl").mockReturnValue("https://example-app.com/api"); + }); + + it("Processes valid request", async () => { + vi.spyOn(middleware, "getSaleorHeaders").mockReturnValue(validHeaders); + + const result = await validator.validateRequest({ + allowedEvent: "PRODUCT_UPDATED", + apl: mockAPL, + adapter, + adapterMiddleware: middleware, + }); + + expect(result).toMatchObject({ + result: "ok", + context: expect.objectContaining({ + baseUrl: "https://example-app.com/api", + event: "product_updated", + payload: {}, + schemaVersion: null, + }), + }); + }); + + it("Throws error on non-POST request method", async () => { + vi.spyOn(adapter, "method", "get").mockReturnValue("GET"); + + const result = await validator.validateRequest({ + allowedEvent: "PRODUCT_UPDATED", + apl: mockAPL, + adapter, + adapterMiddleware: middleware, + }); + + expect(result).toMatchObject({ + result: "failure", + error: expect.objectContaining({ + message: "Wrong request method, only POST allowed", + }), + }); + }); + + it("Throws error on missing api url header", async () => { + vi.spyOn(middleware, "getSaleorHeaders").mockReturnValue({ + ...validHeaders, + // @ts-expect-error testing missing saleorApiUrl + saleorApiUrl: null, + }); + + const result = await validator.validateRequest({ + allowedEvent: "PRODUCT_UPDATED", + apl: mockAPL, + adapter, + adapterMiddleware: middleware, + }); + + expect(result).toMatchObject({ + result: "failure", + error: expect.objectContaining({ + message: "Missing saleor-api-url header", + }), + }); + }); + + it("Throws error on missing event header", async () => { + vi.spyOn(middleware, "getSaleorHeaders").mockReturnValue({ + // @ts-expect-error testing missing event + event: null, + signature: "mocked_signature", + saleorApiUrl: mockAPL.workingSaleorApiUrl, + }); + + const result = await validator.validateRequest({ + allowedEvent: "PRODUCT_UPDATED", + apl: mockAPL, + adapter, + adapterMiddleware: middleware, + }); + + expect(result).toMatchObject({ + result: "failure", + error: expect.objectContaining({ + message: "Missing saleor-event header", + }), + }); + }); + + it("Throws error on mismatched event header", async () => { + vi.spyOn(middleware, "getSaleorHeaders").mockReturnValue({ + ...validHeaders, + event: "different_event", + }); + + const result = await validator.validateRequest({ + allowedEvent: "PRODUCT_UPDATED", + apl: mockAPL, + adapter, + adapterMiddleware: middleware, + }); + + expect(result).toMatchObject({ + result: "failure", + error: expect.objectContaining({ + message: "Wrong incoming request event: different_event. Expected: product_updated", + }), + }); + }); + + it("Throws error on missing signature header", async () => { + vi.spyOn(middleware, "getSaleorHeaders").mockReturnValue({ + ...validHeaders, + // @ts-expect-error testing missing signature + signature: null, + }); + + const result = await validator.validateRequest({ + allowedEvent: "PRODUCT_UPDATED", + apl: mockAPL, + adapter, + adapterMiddleware: middleware, + }); + + expect(result).toMatchObject({ + result: "failure", + error: expect.objectContaining({ + message: "Missing saleor-signature header", + }), + }); + }); + + it("Throws error on missing request body", async () => { + vi.spyOn(adapter, "getRawBody").mockResolvedValue(""); + vi.spyOn(middleware, "getSaleorHeaders").mockReturnValue(validHeaders); + + const result = await validator.validateRequest({ + allowedEvent: "PRODUCT_UPDATED", + apl: mockAPL, + adapter, + adapterMiddleware: middleware, + }); + + expect(result).toMatchObject({ + result: "failure", + error: expect.objectContaining({ + message: "Missing request body", + }), + }); + }); + + it("Throws error on unregistered app", async () => { + const unregisteredApiUrl = "https://not-registered.example.com/graphql/"; + + vi.spyOn(middleware, "getSaleorHeaders").mockReturnValue({ + ...validHeaders, + saleorApiUrl: unregisteredApiUrl, + }); + + const result = await validator.validateRequest({ + allowedEvent: "PRODUCT_UPDATED", + apl: mockAPL, + adapter, + adapterMiddleware: middleware, + }); + + expect(result).toMatchObject({ + result: "failure", + error: expect.objectContaining({ + message: `Can't find auth data for ${unregisteredApiUrl}. Please register the application`, + }), + }); + }); + + it("Fallbacks to null if version is missing in payload", async () => { + vi.spyOn(adapter, "getRawBody").mockResolvedValue(JSON.stringify({})); + vi.spyOn(middleware, "getSaleorHeaders").mockReturnValue(validHeaders); + + const result = await validator.validateRequest({ + allowedEvent: "PRODUCT_UPDATED", + apl: mockAPL, + adapter, + adapterMiddleware: middleware, + }); + + expect(result).toMatchObject({ + result: "ok", + context: expect.objectContaining({ + schemaVersion: null, + }), + }); + }); +}); From 534b64f966252105ccf3347ac46bc967eed954d1 Mon Sep 17 00:00:00 2001 From: Jonatan Witoszek Date: Mon, 27 Jan 2025 14:52:56 +0100 Subject: [PATCH 58/58] Remove aws-lambda runtime library --- package.json | 4 +- pnpm-lock.yaml | 380 ------------------------------------------------- 2 files changed, 1 insertion(+), 383 deletions(-) diff --git a/package.json b/package.json index 7883d79e..cb2be8ed 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,6 @@ "license": "ISC", "peerDependencies": { "@vercel/kv": "^1.0.0", - "aws-lambda": "^1.0.7", "graphql": ">=16.6.0", "next": ">=12", "react": ">=17", @@ -52,7 +51,6 @@ "@typescript-eslint/eslint-plugin": "^5.36.1", "@typescript-eslint/parser": "^7.1.1", "@vercel/kv": "1.0.0", - "aws-lambda": "1.0.7", "@vitejs/plugin-react": "4.3.4", "@vitest/coverage-v8": "3.0.4", "clean-publish": "^4.0.1", @@ -80,8 +78,8 @@ "tsup": "^6.2.3", "typescript": "5.4.2", "vi-fetch": "^0.8.0", - "vite-tsconfig-paths": "^5.1.4", "vite": "6.0.11 ", + "vite-tsconfig-paths": "^5.1.4", "vitest": "3.0.4" }, "peerDependenciesMeta": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9d47354a..0aef50d0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -72,9 +72,6 @@ importers: '@vitest/coverage-v8': specifier: 3.0.4 version: 3.0.4(vitest@3.0.4(@types/debug@4.1.7)(@types/node@18.7.15)(jsdom@20.0.3)) - aws-lambda: - specifier: 1.0.7 - version: 1.0.7 clean-publish: specifier: ^4.0.1 version: 4.0.1 @@ -1139,18 +1136,6 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - available-typed-arrays@1.0.7: - resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} - engines: {node: '>= 0.4'} - - aws-lambda@1.0.7: - resolution: {integrity: sha512-9GNFMRrEMG5y3Jvv+V4azWvc+qNWdWLTjDdhf/zgMlz8haaaLWv0xeAIWxz9PuWUBawsVxy0zZotjCdR3Xq+2w==} - hasBin: true - - aws-sdk@2.1692.0: - resolution: {integrity: sha512-x511uiJ/57FIsbgUe5csJ13k3uzu25uWQE+XqfBis/sB0SFoiElJWXRkgEAUh0U6n40eT3ay5Ue4oPkRMu1LYw==} - engines: {node: '>= 10.0.0'} - axe-core@4.4.3: resolution: {integrity: sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==} engines: {node: '>=4'} @@ -1161,9 +1146,6 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - better-path-resolve@1.0.0: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} @@ -1190,9 +1172,6 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true - buffer@4.9.2: - resolution: {integrity: sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==} - bundle-require@3.1.0: resolution: {integrity: sha512-IIXtAO7fKcwPHNPt9kY/WNVJqy7NDy6YqJvv6ENH0TOZoJ+yjpEsn1w40WKZbR2ibfu5g1rfgJTvmFHpm5aOMA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -1211,21 +1190,9 @@ packages: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} - call-bind-apply-helpers@1.0.1: - resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==} - engines: {node: '>= 0.4'} - call-bind@1.0.2: resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} - call-bind@1.0.8: - resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} - engines: {node: '>= 0.4'} - - call-bound@1.0.3: - resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==} - engines: {node: '>= 0.4'} - callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -1327,9 +1294,6 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} - commander@3.0.2: - resolution: {integrity: sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==} - commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} @@ -1456,10 +1420,6 @@ packages: defaults@1.0.3: resolution: {integrity: sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==} - define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} - define-lazy-prop@2.0.0: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} engines: {node: '>=8'} @@ -1503,10 +1463,6 @@ packages: resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==} engines: {node: '>=12'} - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} @@ -1538,21 +1494,9 @@ packages: resolution: {integrity: sha512-XxXQuVNrySBNlEkTYJoDNFe5+s2yIOpzq80sUHEdPdQr0S5nTLz4ZPPPswNIpKseDDUS5yghX1gfLIHQZ1iNuQ==} engines: {node: '>= 0.4'} - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - es-module-lexer@1.6.0: resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==} - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - es-shim-unscopables@1.0.0: resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} @@ -1994,10 +1938,6 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - events@1.1.1: - resolution: {integrity: sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==} - engines: {node: '>=0.4.x'} - execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -2063,9 +2003,6 @@ packages: flatted@3.2.7: resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} - for-each@0.3.3: - resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} - foreground-child@3.3.0: resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} engines: {node: '>=14'} @@ -2097,9 +2034,6 @@ packages: function-bind@1.1.1: resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - function.prototype.name@1.1.5: resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} engines: {node: '>= 0.4'} @@ -2125,14 +2059,6 @@ packages: get-intrinsic@1.1.2: resolution: {integrity: sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==} - get-intrinsic@1.2.7: - resolution: {integrity: sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==} - engines: {node: '>= 0.4'} - - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} @@ -2152,9 +2078,6 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} - glob-to-regexp@0.4.1: - resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - glob@10.4.5: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true @@ -2187,10 +2110,6 @@ packages: globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - graceful-fs@4.2.10: resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} @@ -2219,33 +2138,18 @@ packages: has-property-descriptors@1.0.0: resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} - has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - has-symbols@1.0.3: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - has-tostringtag@1.0.0: resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} engines: {node: '>= 0.4'} - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - has@1.0.3: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} engines: {node: '>= 0.4.0'} - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} @@ -2292,9 +2196,6 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} - ieee754@1.1.13: - resolution: {integrity: sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==} - ignore@5.2.0: resolution: {integrity: sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==} engines: {node: '>= 4'} @@ -2321,10 +2222,6 @@ packages: resolution: {integrity: sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==} engines: {node: '>= 0.4'} - is-arguments@1.2.0: - resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} - engines: {node: '>= 0.4'} - is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} @@ -2367,10 +2264,6 @@ packages: resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} engines: {node: '>=12'} - is-generator-function@1.1.0: - resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} - engines: {node: '>= 0.4'} - is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -2398,10 +2291,6 @@ packages: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} - is-regex@1.2.1: - resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} - engines: {node: '>= 0.4'} - is-shared-array-buffer@1.0.2: resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} @@ -2425,10 +2314,6 @@ packages: resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} engines: {node: '>= 0.4'} - is-typed-array@1.1.15: - resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} - engines: {node: '>= 0.4'} - is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} @@ -2440,9 +2325,6 @@ packages: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} - isarray@1.0.0: - resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -2465,10 +2347,6 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - jmespath@0.16.0: - resolution: {integrity: sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==} - engines: {node: '>= 0.6.0'} - jose@4.14.4: resolution: {integrity: sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==} @@ -2644,10 +2522,6 @@ packages: resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} engines: {node: '>=8'} - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - media-typer@0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} @@ -2968,10 +2842,6 @@ packages: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} - possible-typed-array-names@1.0.0: - resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} - engines: {node: '>= 0.4'} - postcss-load-config@3.1.4: resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} engines: {node: '>= 10'} @@ -3022,9 +2892,6 @@ packages: psl@1.9.0: resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} - punycode@1.3.2: - resolution: {integrity: sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==} - punycode@2.1.1: resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} engines: {node: '>=6'} @@ -3033,11 +2900,6 @@ packages: resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==} engines: {node: '>=6'} - querystring@0.2.0: - resolution: {integrity: sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==} - engines: {node: '>=0.4.x'} - deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead. - querystringify@2.2.0: resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} @@ -3175,16 +3037,9 @@ packages: safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - safe-regex-test@1.1.0: - resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} - engines: {node: '>= 0.4'} - safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sax@1.2.1: - resolution: {integrity: sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==} - saxes@6.0.0: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} @@ -3217,10 +3072,6 @@ packages: set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} - setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} @@ -3632,21 +3483,11 @@ packages: url-parse@1.5.10: resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} - url@0.10.3: - resolution: {integrity: sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==} - use-sync-external-store@1.2.0: resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 - util@0.12.5: - resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} - - uuid@8.0.0: - resolution: {integrity: sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==} - hasBin: true - uuid@9.0.0: resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==} hasBin: true @@ -3742,10 +3583,6 @@ packages: resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==} engines: {node: '>=14'} - watchpack@2.4.2: - resolution: {integrity: sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==} - engines: {node: '>=10.13.0'} - wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} @@ -3781,10 +3618,6 @@ packages: resolution: {integrity: sha512-Lhs9Pmyph0p5n5Z3mVnN0yWcbQYUAD7rbQUiMsQxOJ3T57k7RFe35SUwWMf7dsbDZks1uOmw4AecB/JMDj3v/w==} engines: {node: '>=8.15'} - which-typed-array@1.1.18: - resolution: {integrity: sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==} - engines: {node: '>= 0.4'} - which@1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} hasBin: true @@ -3834,14 +3667,6 @@ packages: resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} engines: {node: '>=12'} - xml2js@0.6.2: - resolution: {integrity: sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==} - engines: {node: '>=4.0.0'} - - xmlbuilder@11.0.1: - resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} - engines: {node: '>=4.0'} - xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} @@ -4912,38 +4737,12 @@ snapshots: asynckit@0.4.0: {} - available-typed-arrays@1.0.7: - dependencies: - possible-typed-array-names: 1.0.0 - - aws-lambda@1.0.7: - dependencies: - aws-sdk: 2.1692.0 - commander: 3.0.2 - js-yaml: 3.14.1 - watchpack: 2.4.2 - - aws-sdk@2.1692.0: - dependencies: - buffer: 4.9.2 - events: 1.1.1 - ieee754: 1.1.13 - jmespath: 0.16.0 - querystring: 0.2.0 - sax: 1.2.1 - url: 0.10.3 - util: 0.12.5 - uuid: 8.0.0 - xml2js: 0.6.2 - axe-core@4.4.3: {} axobject-query@2.2.0: {} balanced-match@1.0.2: {} - base64-js@1.5.1: {} - better-path-resolve@1.0.0: dependencies: is-windows: 1.0.2 @@ -4974,12 +4773,6 @@ snapshots: node-releases: 2.0.19 update-browserslist-db: 1.1.2(browserslist@4.24.4) - buffer@4.9.2: - dependencies: - base64-js: 1.5.1 - ieee754: 1.1.13 - isarray: 1.0.0 - bundle-require@3.1.0(esbuild@0.15.7): dependencies: esbuild: 0.15.7 @@ -4993,28 +4786,11 @@ snapshots: cac@6.7.14: {} - call-bind-apply-helpers@1.0.1: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - call-bind@1.0.2: dependencies: function-bind: 1.1.1 get-intrinsic: 1.1.2 - call-bind@1.0.8: - dependencies: - call-bind-apply-helpers: 1.0.1 - es-define-property: 1.0.1 - get-intrinsic: 1.2.7 - set-function-length: 1.2.2 - - call-bound@1.0.3: - dependencies: - call-bind-apply-helpers: 1.0.1 - get-intrinsic: 1.2.7 - callsites@3.1.0: {} camelcase-keys@6.2.2: @@ -5123,8 +4899,6 @@ snapshots: dependencies: delayed-stream: 1.0.0 - commander@3.0.2: {} - commander@4.1.1: {} commander@9.4.1: {} @@ -5221,12 +4995,6 @@ snapshots: dependencies: clone: 1.0.4 - define-data-property@1.1.4: - dependencies: - es-define-property: 1.0.1 - es-errors: 1.3.0 - gopd: 1.2.0 - define-lazy-prop@2.0.0: {} define-properties@1.1.4: @@ -5260,12 +5028,6 @@ snapshots: dependencies: webidl-conversions: 7.0.0 - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.1 - es-errors: 1.3.0 - gopd: 1.2.0 - eastasianwidth@0.2.0: {} electron-to-chromium@1.5.88: {} @@ -5315,16 +5077,8 @@ snapshots: string.prototype.trimstart: 1.0.5 unbox-primitive: 1.0.2 - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - es-module-lexer@1.6.0: {} - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - es-shim-unscopables@1.0.0: dependencies: has: 1.0.3 @@ -5769,8 +5523,6 @@ snapshots: esutils@2.0.3: {} - events@1.1.1: {} - execa@5.1.1: dependencies: cross-spawn: 7.0.3 @@ -5855,10 +5607,6 @@ snapshots: flatted@3.2.7: {} - for-each@0.3.3: - dependencies: - is-callable: 1.2.4 - foreground-child@3.3.0: dependencies: cross-spawn: 7.0.3 @@ -5891,8 +5639,6 @@ snapshots: function-bind@1.1.1: {} - function-bind@1.1.2: {} - function.prototype.name@1.1.5: dependencies: call-bind: 1.0.2 @@ -5916,24 +5662,6 @@ snapshots: has: 1.0.3 has-symbols: 1.0.3 - get-intrinsic@1.2.7: - dependencies: - call-bind-apply-helpers: 1.0.1 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - get-stream@6.0.1: {} get-symbol-description@1.0.0: @@ -5951,8 +5679,6 @@ snapshots: dependencies: is-glob: 4.0.3 - glob-to-regexp@0.4.1: {} - glob@10.4.5: dependencies: foreground-child: 3.3.0 @@ -6007,8 +5733,6 @@ snapshots: globrex@0.1.2: {} - gopd@1.2.0: {} - graceful-fs@4.2.10: {} grapheme-splitter@1.0.4: {} @@ -6027,30 +5751,16 @@ snapshots: dependencies: get-intrinsic: 1.1.2 - has-property-descriptors@1.0.2: - dependencies: - es-define-property: 1.0.1 - has-symbols@1.0.3: {} - has-symbols@1.1.0: {} - has-tostringtag@1.0.0: dependencies: has-symbols: 1.0.3 - has-tostringtag@1.0.2: - dependencies: - has-symbols: 1.0.3 - has@1.0.3: dependencies: function-bind: 1.1.1 - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - hosted-git-info@2.8.9: {} html-encoding-sniffer@3.0.0: @@ -6098,8 +5808,6 @@ snapshots: dependencies: safer-buffer: 2.1.2 - ieee754@1.1.13: {} - ignore@5.2.0: {} import-fresh@3.3.0: @@ -6124,11 +5832,6 @@ snapshots: has: 1.0.3 side-channel: 1.0.4 - is-arguments@1.2.0: - dependencies: - call-bound: 1.0.3 - has-tostringtag: 1.0.2 - is-arrayish@0.2.1: {} is-bigint@1.0.4: @@ -6162,13 +5865,6 @@ snapshots: is-fullwidth-code-point@4.0.0: {} - is-generator-function@1.1.0: - dependencies: - call-bound: 1.0.3 - get-proto: 1.0.1 - has-tostringtag: 1.0.2 - safe-regex-test: 1.1.0 - is-glob@4.0.3: dependencies: is-extglob: 2.1.1 @@ -6190,13 +5886,6 @@ snapshots: call-bind: 1.0.2 has-tostringtag: 1.0.0 - is-regex@1.2.1: - dependencies: - call-bound: 1.0.3 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - is-shared-array-buffer@1.0.2: dependencies: call-bind: 1.0.2 @@ -6217,10 +5906,6 @@ snapshots: dependencies: has-symbols: 1.0.3 - is-typed-array@1.1.15: - dependencies: - which-typed-array: 1.1.18 - is-weakref@1.0.2: dependencies: call-bind: 1.0.2 @@ -6231,8 +5916,6 @@ snapshots: dependencies: is-docker: 2.2.1 - isarray@1.0.0: {} - isexe@2.0.0: {} istanbul-lib-coverage@3.2.2: {} @@ -6262,8 +5945,6 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 - jmespath@0.16.0: {} - jose@4.14.4: {} joycon@3.1.1: {} @@ -6464,8 +6145,6 @@ snapshots: map-obj@4.3.0: {} - math-intrinsics@1.1.0: {} - media-typer@0.3.0: {} meow@6.1.1: @@ -6775,8 +6454,6 @@ snapshots: dependencies: find-up: 4.1.0 - possible-typed-array-names@1.0.0: {} - postcss-load-config@3.1.4(postcss@8.5.1): dependencies: lilconfig: 2.0.6 @@ -6825,8 +6502,6 @@ snapshots: psl@1.9.0: {} - punycode@1.3.2: {} - punycode@2.1.1: {} query-string@7.1.3: @@ -6836,8 +6511,6 @@ snapshots: split-on-first: 1.1.0 strict-uri-encode: 2.0.0 - querystring@0.2.0: {} - querystringify@2.2.0: {} queue-microtask@1.2.3: {} @@ -6998,16 +6671,8 @@ snapshots: safe-buffer@5.2.1: {} - safe-regex-test@1.1.0: - dependencies: - call-bound: 1.0.3 - es-errors: 1.3.0 - is-regex: 1.2.1 - safer-buffer@2.1.2: {} - sax@1.2.1: {} - saxes@6.0.0: dependencies: xmlchars: 2.2.0 @@ -7032,15 +6697,6 @@ snapshots: set-blocking@2.0.0: {} - set-function-length@1.2.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.2.7 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - setprototypeof@1.2.0: {} shebang-command@1.2.0: @@ -7420,25 +7076,10 @@ snapshots: querystringify: 2.2.0 requires-port: 1.0.0 - url@0.10.3: - dependencies: - punycode: 1.3.2 - querystring: 0.2.0 - use-sync-external-store@1.2.0(react@18.2.0): dependencies: react: 18.2.0 - util@0.12.5: - dependencies: - inherits: 2.0.4 - is-arguments: 1.2.0 - is-generator-function: 1.1.0 - is-typed-array: 1.1.15 - which-typed-array: 1.1.18 - - uuid@8.0.0: {} - uuid@9.0.0: {} validate-npm-package-license@3.0.4: @@ -7536,11 +7177,6 @@ snapshots: dependencies: xml-name-validator: 4.0.0 - watchpack@2.4.2: - dependencies: - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.10 - wcwidth@1.0.1: dependencies: defaults: 1.0.3 @@ -7581,15 +7217,6 @@ snapshots: load-yaml-file: 0.2.0 path-exists: 4.0.0 - which-typed-array@1.1.18: - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.8 - call-bound: 1.0.3 - for-each: 0.3.3 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - which@1.3.1: dependencies: isexe: 2.0.0 @@ -7629,13 +7256,6 @@ snapshots: xml-name-validator@4.0.0: {} - xml2js@0.6.2: - dependencies: - sax: 1.2.1 - xmlbuilder: 11.0.1 - - xmlbuilder@11.0.1: {} - xmlchars@2.2.0: {} y18n@4.0.3: {}