From d2696c46ba529dade19a27e4be1fb38fdbf247ab Mon Sep 17 00:00:00 2001 From: Carlos Sanjines Aldazosa Date: Mon, 27 Nov 2023 08:33:31 -0400 Subject: [PATCH] Oauth providers (#262) * [FEAT] facebook and google authentication * [FEAT] github authentication * [FEAT] linkedin authentication * [TEST] all methods tested * [UPDATE] open-auth middleware split * [UPDATE] auth packages merged into oauth-provider * docs: format README * fix: fix `package.json`, prettify, rename something * fix: use `ContextVariableMap` * docs: update README * make it as a minor release * [FIX: linkedin] path name * [UPDATE: linkedin] pathname --------- Co-authored-by: Yusuke Wada --- .changeset/thick-olives-invent.md | 5 + packages/oauth-providers/CHANGELOG.md | 0 packages/oauth-providers/README.md | 631 ++++++++ packages/oauth-providers/jest.config.js | 7 + packages/oauth-providers/package.json | 102 ++ packages/oauth-providers/src/index.ts | 1 + .../src/providers/facebook/authFlow.ts | 114 ++ .../src/providers/facebook/facebookAuth.ts | 61 + .../src/providers/facebook/index.ts | 10 + .../src/providers/facebook/types.ts | 130 ++ .../src/providers/github/authFlow.ts | 105 ++ .../src/providers/github/githubAuth.ts | 57 + .../src/providers/github/index.ts | 10 + .../src/providers/github/types.ts | 97 ++ .../src/providers/google/authFlow.ts | 119 ++ .../src/providers/google/googleAuth.ts | 62 + .../src/providers/google/index.ts | 11 + .../src/providers/google/revokeToken.ts | 8 + .../src/providers/google/types.ts | 38 + .../src/providers/linkedin/authFlow.ts | 136 ++ .../src/providers/linkedin/index.ts | 11 + .../src/providers/linkedin/linkedinAuth.ts | 61 + .../src/providers/linkedin/refreshToken.ts | 28 + .../src/providers/linkedin/types.ts | 51 + packages/oauth-providers/src/types.ts | 10 + .../src/utils/getRandomState.ts | 7 + .../src/utils/objectToQuery.ts | 12 + packages/oauth-providers/test/handlers.ts | 264 ++++ packages/oauth-providers/test/index.test.ts | 361 +++++ packages/oauth-providers/tsconfig.json | 10 + packages/oauth-providers/tsup.config.ts | 9 + yarn.lock | 1365 ++++++++++++++++- 32 files changed, 3886 insertions(+), 7 deletions(-) create mode 100644 .changeset/thick-olives-invent.md create mode 100644 packages/oauth-providers/CHANGELOG.md create mode 100644 packages/oauth-providers/README.md create mode 100644 packages/oauth-providers/jest.config.js create mode 100644 packages/oauth-providers/package.json create mode 100644 packages/oauth-providers/src/index.ts create mode 100644 packages/oauth-providers/src/providers/facebook/authFlow.ts create mode 100644 packages/oauth-providers/src/providers/facebook/facebookAuth.ts create mode 100644 packages/oauth-providers/src/providers/facebook/index.ts create mode 100644 packages/oauth-providers/src/providers/facebook/types.ts create mode 100644 packages/oauth-providers/src/providers/github/authFlow.ts create mode 100644 packages/oauth-providers/src/providers/github/githubAuth.ts create mode 100644 packages/oauth-providers/src/providers/github/index.ts create mode 100644 packages/oauth-providers/src/providers/github/types.ts create mode 100644 packages/oauth-providers/src/providers/google/authFlow.ts create mode 100644 packages/oauth-providers/src/providers/google/googleAuth.ts create mode 100644 packages/oauth-providers/src/providers/google/index.ts create mode 100644 packages/oauth-providers/src/providers/google/revokeToken.ts create mode 100644 packages/oauth-providers/src/providers/google/types.ts create mode 100644 packages/oauth-providers/src/providers/linkedin/authFlow.ts create mode 100644 packages/oauth-providers/src/providers/linkedin/index.ts create mode 100644 packages/oauth-providers/src/providers/linkedin/linkedinAuth.ts create mode 100644 packages/oauth-providers/src/providers/linkedin/refreshToken.ts create mode 100644 packages/oauth-providers/src/providers/linkedin/types.ts create mode 100644 packages/oauth-providers/src/types.ts create mode 100644 packages/oauth-providers/src/utils/getRandomState.ts create mode 100644 packages/oauth-providers/src/utils/objectToQuery.ts create mode 100644 packages/oauth-providers/test/handlers.ts create mode 100644 packages/oauth-providers/test/index.test.ts create mode 100644 packages/oauth-providers/tsconfig.json create mode 100644 packages/oauth-providers/tsup.config.ts diff --git a/.changeset/thick-olives-invent.md b/.changeset/thick-olives-invent.md new file mode 100644 index 00000000..3d2a3efa --- /dev/null +++ b/.changeset/thick-olives-invent.md @@ -0,0 +1,5 @@ +--- +'@hono/oauth-providers': minor +--- + +Add oauth-providers middleware diff --git a/packages/oauth-providers/CHANGELOG.md b/packages/oauth-providers/CHANGELOG.md new file mode 100644 index 00000000..e69de29b diff --git a/packages/oauth-providers/README.md b/packages/oauth-providers/README.md new file mode 100644 index 00000000..6bbce6ba --- /dev/null +++ b/packages/oauth-providers/README.md @@ -0,0 +1,631 @@ +# OAuth Providers Middleware + +Authentication middleware for [Hono](https://github.com/honojs/hono). This package offers a straightforward API for social login with platforms such as Facebook, GitHub, Google, and LinkedIn. + +## Installation + +You can install `hono` and `@hono/oauth-providers` via npm. + +```txt +npm i hono @hono/oauth-providers +``` + +## Usage + +Open Auth simplifies the OAuth2 flow, enabling you to utilize social login with just a single method. +On every platform you choose to add to your project you have to add on its platform the **callback uri** or **redirect uri**. Open Auth handles the redirect uri internally as the route you are using the middleware on, so if you decide to use the google auth on the route `/api/v1/auth/google/` the redirect uri will be `DOMAIN/api/v1/auth/google`. + +```ts +app.use( + "api/v1/auth/google", // -> redirect_uri by default + googleAuth({ ... }) +) +``` + +Also, there is two ways to use this middleware: + +```ts +app.use( + '/google', + googleAuth({ + client_id: Bun.env.GOOGLE_ID, + client_secret: Bun.env.GOOGLE_SECRET, + scope: ['openid', 'email', 'profile'], + }) +) + +app.get('/google', (c) => { + const token = c.get('token') + const grantedScopes = c.get('granted-scopes') + const user = c.get('user-google') + + return c.json({ + token, + grantedScopes, + user, + }) +}) + +export default app +``` + +Or + +```ts +app.get( + '/google', + googleAuth({ + client_id: Bun.env.GOOGLE_ID, + client_secret: Bun.env.GOOGLE_SECRET, + scope: ['openid', 'email', 'profile'], + }), + (c) => { + const token = c.get('token') + const grantedScopes = c.get('granted-scopes') + const user = c.get('user-google') + + return c.json({ + token, + grantedScopes, + user, + }) + } +) + +export default app +``` + +### Google + +```ts +import { Hono } from 'hono' +import { googleAuth } from '@hono/oauth-providers/google' + +const app = new Hono() + +app.use( + '/google', + googleAuth({ + client_id: Bun.env.GOOGLE_ID, + client_secret: Bun.env.GOOGLE_SECRET, + scope: ['openid', 'email', 'profile'], + }) +) + +export default app +``` + +#### Parameters + +- `client_id`: + - Type: `string`. + - `Required`. + - Your app client ID. You can find this value in the API Console [Credentials page](https://console.developers.google.com/apis/credentials).
When developing **Cloudflare Workers**, there's no need to send this parameter. Just declare it in the `wrangler.toml` file as `GOOGLE_ID=`. +- `client_secret`: + - Type: `string`. + - `Required`. + - Your app client secret. You can find this value in the API Console [Credentials page](https://console.developers.google.com/apis/credentials).
When developing **Cloudflare Workers**, there's no need to send this parameter. Just declare it in the `wrangler.toml` file as `GOOGLE_SECRET=`. + > Do not share your client secret to ensure the security of your app. +- `scope`: + - Type: `string[]`. + - `Required`. + - Set of **permissions** to request the user's authorization to access your app for retrieving user information and performing actions on their behalf.
Review all the scopes Google offers for utilizing their API on the [OAuth 2.0 Scopes page](https://developers.google.com/identity/protocols/oauth2/scopes). + > If your app is not **verified** by Google, the accessible scopes for your app are significantly **limited**. +- `login_hint`: + - Type: `string`. + - `Optional`. + - Set the parameter value to an email address or `sub` identifier to provide a hint to the Google Authentication Server who is asking for authentication. +- `prompt`: + - Type: `string`. + - `Optional`. + - Define the prompt the user will receive when logging into their Google account. If not sent, the user will only be prompted the first time your project requests access.
Choose one of the following options: + - `none`: Do not display any authentication or consent screens. Must not be specified with other values. + - `consent`: Prompt the user for consent. + - `select_account`: Prompt the user to select an account. + +#### Authentication Flow + +After the completion of the Google OAuth flow, essential data has been prepared for use in the subsequent steps that your app needs to take. + +`googleAuth` method provides 3 set key data: + +- `token`: + - Access token to make requests to the google API for retrieving user information and performing actions on their behalf. + - Type: + ``` + { + token: string + expires_in: number + } + ``` +- `granted-scopes`: + - If the `include_granted_scopes` parameter was set to `true`, you can find here the scopes for which the user has granted permissions. + - Type: `string[]`. +- `user-google`: + - User basic info retrieved from Google + - Type: + ``` + { + id: string + email: string + verified_email: boolean + name: string + given_name: string + family_name: string + picture: string + locale: string + } + ``` + +To access this data, utilize the `c.get` method within the callback of the upcoming HTTP request handler. + +```ts +app.get('/google', (c) => { + const token = c.get('token') + const grantedScopes = c.get('granted-scopes') + const user = c.get('user-google') + + return c.json({ + token, + grantedScopes, + user, + }) +}) +``` + +#### Revoke Token + +In certain use cases, you may need to programmatically revoke a user's access token. In such scenarios, you can utilize the `revokeToken` method, which accepts the `token` to be revoked as its unique parameter. + +```ts +import { googleAuth, revokeToken } from 'open-auth/google' + +app.post('/remove-user', async (c, next) => { + await revokeToken(USER_TOKEN) + + // ... +}) +``` + +### Facebook + +```ts +import { Hono } from 'hono' +import { facebookAuth } from '@hono/oauth-providers/facebook' + +const app = new Hono() + +app.use( + '/facebook', + facebookAuth({ + client_id: Bun.env.FACEBOOK_ID, + client_secret: Bun.env.FACEBOOK_SECRET, + scope: ['email', 'public_profile'], + fields: [ + 'email', + 'id', + 'first_name', + 'last_name', + 'middle_name', + 'name', + 'picture', + 'short_name', + ], + }) +) + +export default app +``` + +#### Parameters + +- `client_id`: + - Type: `string`. + - `Required`. + - Your app client ID. You can find this value in the App Dashboard [Dashboard page](https://developers.facebook.com/apps).
When developing **Cloudflare Workers**, there's no need to send this parameter. Just declare it in the `wrangler.toml` file as `FACEBOOK_ID=`. +- `client_secret`: + - Type: `string`. + - `Required`. + - Your app client secret. You can find this value in the App Dashboard [Dashboard page](https://developers.facebook.com/apps).
When developing **Cloudflare Workers**, there's no need to send this parameter. Just declare it in the `wrangler.toml` file as `FACEBOOK_SECRET=`. + > Do not share your client secret to ensure the security of your app. +- `scope`: + - Type: `string[]`. + - `Required`. + - Set of **permissions** to request the user's authorization to access your app for retrieving user information and performing actions on their behalf.
Review all the scopes Facebook offers for utilizing their API on the [Permissions page](https://developers.facebook.com/docs/permissions/). + > If your app is not **verified** by Facebook, the accessible scopes for your app are significantly **limited**. +- `fields`: + - Type: `string[]`. + - Fields you request from the Facebook API to be sent once the user has logged in. You can find a comprehensive reference for all the fields you can request on the [Facebook User Reference page](https://developers.facebook.com/docs/graph-api/reference/user/#fields). + +#### Authentication Flow + +After the completion of the Facebook OAuth flow, essential data has been prepared for use in the subsequent steps that your app needs to take. + +`facebookAuth` method provides 3 set key data: + +- `token`: + - Access token to make requests to the Facebook API for retrieving user information and performing actions on their behalf. It has a duration of 60 days. + - Type: + ``` + { + token: string + expires_in: number + } + ``` +- `granted-scopes`: + - If the `include_granted_scopes` parameter was set to `true`, you can find here the scopes for which the user has granted permissions. + - Type: `string[]`. +- `user-facebook`: + - User basic info retrieved from Facebook + - Type: + ``` + { + id: string + name: string + email: string + picture: { + data: { + height: number + is_silhouette: boolean + url: string + width: number + } + } + first_name: string + last_name: string + short_name: string + } + ``` + +To access this data, utilize the `c.get` method within the callback of the upcoming HTTP request handler. + +```ts +app.get('/facebook', (c) => { + const token = c.get('token') + const grantedScopes = c.get('granted-scopes') + const user = c.get('user-facebook') + + return c.json({ + token, + grantedScopes, + user, + }) +}) +``` + +### GitHub + +GitHub provides two types of Apps to utilize its API: the `GitHub App` and the `OAuth App`. To understand the differences between these apps, you can read this [article](https://docs.github.com/en/apps/creating-github-apps/about-creating-github-apps/deciding-when-to-build-a-github-app) from GitHub, helping you determine the type of App you should select. + +#### Parameters + +- `client_id`: + - Type: `string`. + - `Required`. + - `Github App` and `Oauth App`. + - Your app client ID. You can find this value in the [GitHub App settings](https://github.com/settings/apps) or the [OAuth App settings](https://github.com/settings/developers) based on your App type.
When developing **Cloudflare Workers**, there's no need to send this parameter. Just declare it in the `wrangler.toml` file as `GITHUB_ID=`. +- `client_secret`: + - Type: `string`. + - `Required`. + - `Github App` and `Oauth App`. + - Your app client secret. You can find this value in the [GitHub App settings](https://github.com/settings/apps) or the [OAuth App settings](https://github.com/settings/developers) based on your App type.
When developing **Cloudflare Workers**, there's no need to send this parameter. Just declare it in the `wrangler.toml` file as `GITHUB_SECRET=`. + > Do not share your client secret to ensure the security of your app. +- `scope`: + - Type: `string[]`. + - `Required`. + - `Oauth App`. + - Set of **permissions** to request the user's authorization to access your app for retrieving user information and performing actions on their behalf.
Review all the scopes Github offers for utilizing their API on the [Permissions page](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/scopes-for-oauth-apps).
For `GitHub Apps`, you select the scopes during the App creation process or in the [settings](https://github.com/settings/apps). +- `oauthApp`: + - Type: `boolean`. + - `Required`. + - `Oauth App`. + - Set this value to `true` if your App is of the OAuth App type. Defaults to `false`. + +#### Authentication Flow + +After the completion of the Github Auth flow, essential data has been prepared for use in the subsequent steps that your app needs to take. + +`githubAuth` method provides 4 set key data: + +- `token`: + - Access token to make requests to the Github API for retrieving user information and performing actions on their behalf. + - Type: + ``` + { + token: string + expires_in: number // -> only available for Oauth Apps + } + ``` +- `refresh-token`: + - You can refresh new tokens using this token, which has a longer lifespan. Only available for Oauth Apps. + - Type: + ``` + { + token: string + expires_in: number + } + ``` +- `user-github`: + - User basic info retrieved from Github + - Type: + ``` + { + login: string + id: number + node_id: string + avatar_url: string + gravatar_id: string + url: string + html_url: string + followers_url: string + following_url: string + gists_url: string + starred_url: string + subscriptions_url: string + organizations_url: string + repos_url: string + events_url: string + received_events_url: string + type: string + site_admin: boolean + name: string + company: string + blog: string + location: string + email: string | null + hireable: boolean | null + bio: string + twitter_username: string + public_repos: number + public_gists: number + followers: number + following: number + created_at: string + updated_at: string + private_gists: number, // -> Github App + total_private_repos: number, // -> Github App + owned_private_repos: number, // -> Github App + disk_usage: number, // -> Github App + collaborators: number, // -> Github App + two_factor_authentication: boolean, // -> Github App + plan: { + name: string, + space: number, + collaborators: number, + private_repos: number + } // -> Github App + } + ``` +- `granted-scopes`: + - If the `include_granted_scopes` parameter was set to `true`, you can find here the scopes for which the user has granted permissions. + +#### Github App Example + +```ts +import { Hono } from 'hono' +import { githubAuth } from '@hono/oauth-providers/github' + +const app = new Hono() + +app.use( + '/github', + githubAuth({ + client_id: Bun.env.GITHUB_ID, + client_secret: Bun.env.GITHUB_SECRET, + }) +) + +app.get('/github', (c) => { + const token = c.get('token') + const user = c.get('user-github') + + return c.json({ + token, + user, + }) +}) + +export default app +``` + +#### OAuth App Example + +```ts +import { Hono } from 'hono' +import { githubAuth } from '@hono/oauth-providers/github' + +const app = new Hono() + +app.use( + '/github', + githubAuth({ + client_id: Bun.env.GITHUB_ID, + client_secret: Bun.env.GITHUB_SECRET, + scope: ['public_repo', 'read:user', 'user', 'user:email', 'user:follow'], + oauthApp: true, + }) +) + +app.get('/github', (c) => { + const token = c.get('token') + const refreshToken = c.get('refresh-token') + const user = c.get('user-github') + + return c.json({ + token, + refreshToken, + user, + }) +}) + +export default app +``` + +### LinkedIn + +LinkedIn provides two types of Authorization to utilize its API: the `Member Authotization` and the `Application Authorization`. To understand the differences between these authorization methods, you can read this [article](https://learn.microsoft.com/en-us/linkedin/shared/authentication/authentication?context=linkedin%2Fcontext) from LinkedIn, helping you determine the type of Authorization your app should use. + +#### Parameters + +- `client_id`: + - Type: `string`. + - `Required`. + - `Member` and `Application` authorization. + - Your app client ID. You can find this value in the [LinkedIn Developer Portal](https://www.linkedin.com/developers/apps).
When developing **Cloudflare Workers**, there's no need to send this parameter. Just declare it in the `wrangler.toml` file as `LINKEDIN_ID=`. +- `client_secret`: + - Type: `string`. + - `Required`. + - `Member` and `Application` authorization. + - Your app client secret. You can find this value in the [LinkedIn Developer Portal](https://www.linkedin.com/developers/apps).
When developing **Cloudflare Workers**, there's no need to send this parameter. Just declare it in the `wrangler.toml` file as `LINKEDIN_SECRET=`. + > Do not share your client secret to ensure the security of your app. +- `scope`: + - Type: `string[]`. + - `Required`. + - `Member Authorization`. + - Set of **permissions** to request the user's authorization to access your app for retrieving user information and performing actions on their behalf.
Review all the scopes LinkedIn offers for utilizing their API on the [Getting Access docs page](https://learn.microsoft.com/en-us/linkedin/shared/authentication/getting-access). +- `appAuth`: - Type: `boolean`. - `Required`. - `Application Authorization`. - Set this value to `true` if your App uses the App Authorization method. Defaults to `false`. + > To access the Application Authorization method you have to ask LinkedIn for It. Apparently you have to verify your app then ask for access. + +#### Authentication Flow + +After the completion of the LinkedIn Auth flow, essential data has been prepared for use in the subsequent steps that your app needs to take. + +`linkedinAuth` method provides 4 set key data: + +- `token`: + - Access token to make requests to the LinkedIn API for retrieving user information and performing actions on their behalf. + - Type: + ``` + { + token: string + expires_in: number + } + ``` +- `refresh-token`: + - You can refresh new tokens using this token, which has a longer lifespan. Only available for Member Authorization. + - Type: + ``` + { + token: string + expires_in: number + } + ``` +- `user-linkedin`: + - User basic info retrieved from LinkedIn. + - Type: + ``` + { + sub: string + email_verified: boolean + name: string + locale: { + country: string + language: string + }, + given_name: string + family_name: string + email: string + picture: string + } + ``` + > Only available for Member Authorization. +- `granted-scopes`: + - If the `include_granted_scopes` parameter was set to `true`, you can find here the scopes for which the user has granted permissions. + +#### Member Authentication Example + +```ts +import { Hono } from 'hono' +import { linkedinAuth } from '@hono/oauth-providers/linkedin' + +const app = new Hono() + +app.use( + '/linkedin', + linkedinAuth({ + client_id: Bun.env.LINKEDIN_ID, + client_secret: Bun.env.LINKEDIN_SECRET, + scope: ['email', 'openid', 'profile'], + }) +) + +app.get('/linkedin', (c) => { + const token = c.get('token') + const user = c.get('user-linkedin') + + return c.json({ + token, + user, + }) +}) + +export default app +``` + +#### Application Example + +```ts +import { Hono } from 'hono' +import { linkedinAuth } from '@hono/oauth-providers/linkedin' + +const app = new Hono() + +app.use( + '/linkedin', + linkedinAuth({ + client_id: Bun.env.LINKEDIN_ID, + client_secret: Bun.env.LINKEDIN_SECRET, + appAuth: true, + }) +) + +app.get('/linkedin', (c) => { + const token = c.get('token') + + return c.json(token) +}) + +export default app +``` + +#### Revoke Token + +In certain use cases, you may need to programmatically revoke a user's access token. In such scenarios, you can utilize the `revokeToken` method. + +**Parameters**: + +- `client_id`: + - `string`. +- client_secret: + - `string`. +- `refresh_token`: + - `string`. + +**Return Value**: + +- `token`: + - `string`. + +```ts +import { linkedinAuth, refreshToken } from 'open-auth/linkedin' + +app.post('linkedin/refresh-token', async (c, next) => { + const token = await refreshToken(LINKEDIN_ID, LINKEDIN_SECRET, USER_REFRESH_TOKEN) + + // ... +}) +``` + +## Author + +monoald https://github.com/monoald + +## License + +MIT + +## Contribute + +If you want to add new providers, features or solve some bugs don't doubt to create an issue or make a PR. + +For testing purposes run the following code in the parent folder (`middleware/`): diff --git a/packages/oauth-providers/jest.config.js b/packages/oauth-providers/jest.config.js new file mode 100644 index 00000000..0df57874 --- /dev/null +++ b/packages/oauth-providers/jest.config.js @@ -0,0 +1,7 @@ +module.exports = { + ...require('../../jest.config.js'), + testEnvironmentOptions: { + customExportConditions: [''], + }, + modulePathIgnorePatterns: ['handlers'] +} \ No newline at end of file diff --git a/packages/oauth-providers/package.json b/packages/oauth-providers/package.json new file mode 100644 index 00000000..1b1c875e --- /dev/null +++ b/packages/oauth-providers/package.json @@ -0,0 +1,102 @@ +{ + "name": "@hono/oauth-providers", + "version": "0.0.0", + "description": "Social login for Hono JS, integrate authentication with facebook, github, google and linkedin to your projects.", + "main": "dist/index.js", + "files": [ + "./dist" + ], + "scripts": { + "test": "jest", + "build": "tsup && publint", + "watch": "tsup --watch", + "publint": "publint", + "release": "yarn build && yarn test && yarn publint && yarn publish" + }, + "exports": { + ".": { + "import": { + "types": "./dist/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, + "./google": { + "import": { + "types": "./dist/providers/google/index.d.mts", + "default": "./dist/providers/google/index.mjs" + }, + "require": { + "types": "./dist/providers/google/index.d.ts", + "default": "./dist/providers/google/index.js" + } + }, + "./facebook": { + "import": { + "types": "./dist/providers/facebook/index.d.mts", + "default": "./dist/providers/facebook/index.mjs" + }, + "require": { + "types": "./dist/providers/facebook/index.d.ts", + "default": "./dist/providers/facebook/index.js" + } + }, + "./github": { + "import": { + "types": "./dist/providers/github/index.d.mts", + "default": "./dist/providers/github/index.mjs" + }, + "require": { + "types": "./dist/providers/github/index.d.ts", + "default": "./dist/providers/github/index.js" + } + }, + "./linkedin": { + "import": { + "types": "./dist/providers/linkedin/index.d.mts", + "default": "./dist/providers/linkedin/index.mjs" + }, + "require": { + "types": "./dist/providers/linkedin/index.d.ts", + "default": "./dist/providers/linkedin/index.js" + } + } + }, + "typesVersions": { + "*": { + "facebook": [ + "./dist/providers/facebook/index.d.ts" + ], + "github": [ + "./dist/providers/github/index.d.ts" + ], + "google": [ + "./dist/providers/google/index.d.ts" + ], + "linkedin": [ + "./dist/providers/linkedin/index.d.ts" + ] + } + }, + "peerDependencies": { + "hono": "^3.0.0" + }, + "devDependencies": { + "@cloudflare/workers-types": "^4.20231025.0", + "@types/jest": "^29.5.7", + "hono": "^3.9.2", + "jest": "^29.7.0", + "jest-environment-miniflare": "^2.14.1", + "msw": "^2.0.4", + "patch-package": "^8.0.0", + "ts-jest": "^29.1.1", + "tsup": "^8.0.0", + "typescript": "^5.2.2" + }, + "engines": { + "node": ">=18.4.0" + } +} \ No newline at end of file diff --git a/packages/oauth-providers/src/index.ts b/packages/oauth-providers/src/index.ts new file mode 100644 index 00000000..74c61c3c --- /dev/null +++ b/packages/oauth-providers/src/index.ts @@ -0,0 +1 @@ +export { OAuthVariables } from './types' diff --git a/packages/oauth-providers/src/providers/facebook/authFlow.ts b/packages/oauth-providers/src/providers/facebook/authFlow.ts new file mode 100644 index 00000000..6833f7e1 --- /dev/null +++ b/packages/oauth-providers/src/providers/facebook/authFlow.ts @@ -0,0 +1,114 @@ +import { HTTPException } from 'hono/http-exception' + +import type { Token } from '../../types' +import { toQueryParams } from '../../utils/objectToQuery' +import type { + FacebookErrorResponse, + FacebookMeResponse, + FacebookTokenResponse, + FacebookUser, + Fields, + Permissions, +} from './types' + +type FacebookAuthFlow = { + client_id: string + client_secret: string + redirect_uri: string + scope: Permissions[] + fields: Fields[] + state: string + code: string | undefined + token: Token | undefined +} + +export class AuthFlow { + client_id: string + client_secret: string + redirect_uri: string + scope: Permissions[] + fields: Fields[] + state: string + code: string | undefined + token: Token | undefined + user: Partial | undefined + + constructor({ + client_id, + client_secret, + redirect_uri, + scope, + state, + fields, + code, + token, + }: FacebookAuthFlow) { + this.client_id = client_id + this.client_secret = client_secret + this.redirect_uri = redirect_uri + this.scope = scope + this.fields = fields + this.state = state + this.code = code + this.token = token + this.user = undefined + } + + redirect() { + const parsedOptions = toQueryParams({ + client_id: this.client_id, + redirect_uri: this.redirect_uri, + response_type: ['code', 'granted_scopes'], + scope: this.scope, + state: this.state, + }) + return `https://www.facebook.com/v18.0/dialog/oauth?${parsedOptions}` + } + + private async getTokenFromCode() { + const parsedOptions = toQueryParams({ + client_id: this.client_id, + redirect_uri: this.redirect_uri, + client_secret: this.client_secret, + code: this.code, + }) + const url = `https://graph.facebook.com/v18.0/oauth/access_token?${parsedOptions}` + + const response = (await fetch(url).then((res) => res.json())) as + | FacebookTokenResponse + | FacebookErrorResponse + + if ('error' in response) throw new HTTPException(400, { message: response.error?.message }) + + if ('access_token' in response) { + this.token = { + token: response.access_token, + expires_in: response.expires_in, + } + } + } + + private async getUserId() { + const response = (await fetch( + `https://graph.facebook.com/v18.0/me?access_token=${this.token?.token}` + ).then((res) => res.json())) as FacebookMeResponse | FacebookErrorResponse + + if ('error' in response) throw new HTTPException(400, { message: response.error?.message }) + + if ('id' in response) this.user = response + } + + async getUserData() { + await this.getTokenFromCode() + + await this.getUserId() + const parsedFields = this.fields.join() + const response = (await fetch( + `https://graph.facebook.com/${this.user?.id}?fields=${parsedFields}&access_token=${this.token?.token}` + ).then((res) => res.json())) as FacebookUser | FacebookErrorResponse + + if ('error' in response) throw new HTTPException(400, { message: response.error?.message }) + + if ('id' in response) this.user = response + } +} diff --git a/packages/oauth-providers/src/providers/facebook/facebookAuth.ts b/packages/oauth-providers/src/providers/facebook/facebookAuth.ts new file mode 100644 index 00000000..448cb299 --- /dev/null +++ b/packages/oauth-providers/src/providers/facebook/facebookAuth.ts @@ -0,0 +1,61 @@ +import type { MiddlewareHandler } from 'hono' +import { setCookie, getCookie } from 'hono/cookie' +import { HTTPException } from 'hono/http-exception' + +import { getRandomState } from '../../utils/getRandomState' +import { AuthFlow } from './authFlow' +import type { Fields, Permissions } from './types' + +export function facebookAuth(options: { + scope: Permissions[] + fields: Fields[] + client_id?: string + client_secret?: string +}): MiddlewareHandler { + return async (c, next) => { + const newState = getRandomState() + // Create new Auth instance + const auth = new AuthFlow({ + client_id: options.client_id || (c.env?.FACEBOOK_ID as string), + client_secret: options.client_secret || (c.env?.FACEBOOK_SECRET as string), + redirect_uri: c.req.url.split('?')[0], + scope: options.scope, + fields: options.fields, + state: newState, + code: c.req.query('code'), + token: { + token: c.req.query('access_token') as string, + expires_in: Number(c.req.query('expires_in')), + }, + }) + + // Avoid CSRF attack by checking state + if (c.req.url.includes('?')) { + const storedState = getCookie(c, 'state') + if (c.req.query('state') !== storedState) { + throw new HTTPException(401) + } + } + + // Redirect to login dialog + if (!auth.code) { + setCookie(c, 'state', newState, { + maxAge: 60 * 10, + httpOnly: true, + path: '/', + // secure: true, + }) + return c.redirect(auth.redirect()) + } + + // Retrieve user data from facebook + await auth.getUserData() + + // Set return info + c.set('token', auth.token) + c.set('user-facebook', auth.user) + c.set('granted-scopes', c.req.query('granted_scopes')?.split(',')) + + await next() + } +} diff --git a/packages/oauth-providers/src/providers/facebook/index.ts b/packages/oauth-providers/src/providers/facebook/index.ts new file mode 100644 index 00000000..3750a717 --- /dev/null +++ b/packages/oauth-providers/src/providers/facebook/index.ts @@ -0,0 +1,10 @@ +import type { OAuthVariables } from '../../types' +import type { FacebookUser } from './types' +export { facebookAuth } from './facebookAuth' +export * from './types' + +declare module 'hono' { + interface ContextVariableMap extends OAuthVariables { + 'user-facebook': Partial | undefined + } +} diff --git a/packages/oauth-providers/src/providers/facebook/types.ts b/packages/oauth-providers/src/providers/facebook/types.ts new file mode 100644 index 00000000..45186d1b --- /dev/null +++ b/packages/oauth-providers/src/providers/facebook/types.ts @@ -0,0 +1,130 @@ +export type Permissions = + | 'ads_management' + | 'ads_read' + | 'attribution_read' + | 'business_management' + | 'catalog_management' + | 'email' + | 'gaming_user_locale' + | 'groups_access_member_info' + | 'instagram_basic' + | 'instagram_content_publish' + | 'instagram_graph_user_media' + | 'instagram_graph_user_profile' + | 'instagram_manage_comments' + | 'instagram_manage_insights' + | 'instagram_manage_messages' + | 'instagram_shopping_tag_products' + | 'leads_retrieval' + | 'manage_fundraisers' + | 'pages_events' + | 'pages_manage_ads' + | 'pages_manage_cta' + | 'pages_manage_instant_articles' + | 'pages_manage_engagement' + | 'pages_manage_metadata' + | 'pages_manage_posts' + | 'pages_messaging' + | 'pages_read_engagement' + | 'pages_read_user_content' + | 'pages_show_list' + | 'pages_user_gender' + | 'pages_user_locale' + | 'pages_user_timezone' + | 'private_computation_access' + | 'public_profile' + | 'publish_to_groups' + | 'publish_video' + | 'read_insights' + | 'user_age_range' + | 'user_birthday' + | 'user_friends' + | 'user_gender' + | 'user_hometown' + | 'user_likes' + | 'user_link' + | 'user_location' + | 'user_messenger_contact' + | 'user_photos' + | 'user_posts' + | 'user_videos' + | 'whatsapp_business_management' + | 'whatsapp_business_messaging' + +export type Fields = + | 'id' + | 'first_name' + | 'last_name' + | 'middle_name' + | 'name' + | 'name_format' + | 'picture' + | 'short_name' + | 'about' + | 'age_range' + | 'birthday' + | 'education' + | 'email' + | 'favorite_athletes' + | 'favorite_teams' + | 'gender' + | 'hometown' + | 'id_for_avatars' + | 'inspirational_people' + | 'install_type' + | 'installed' + | 'is_guest_user' + | 'languages' + | 'link' + | 'location' + | 'meeting_for' + | 'middle_name' + | 'payment_pricepoints' + | 'political' + | 'profile_pic' + | 'quotes' + | 'relationship_status' + | 'shared_login_upgrade_required_by' + | 'significant_other' + | 'sports' + | 'supports_donate_button_in_live_video' + | 'token_for_business' + | 'website' + | '' + +export type FacebookErrorResponse = { + error?: { + message: string + type: string + code: number + fbtrace_id: string + } +} + +export type FacebookTokenResponse = { + access_token: string + token_type: string + expires_in: number +} + +export type FacebookMeResponse = { + name: string + id: string +} + +export type FacebookUser = { + id: string + name: string + email: string + picture: { + data: { + height: number + is_silhouette: boolean + url: string + width: number + } + } + first_name: string + last_name: string + short_name: string +} diff --git a/packages/oauth-providers/src/providers/github/authFlow.ts b/packages/oauth-providers/src/providers/github/authFlow.ts new file mode 100644 index 00000000..743427fe --- /dev/null +++ b/packages/oauth-providers/src/providers/github/authFlow.ts @@ -0,0 +1,105 @@ +import { HTTPException } from 'hono/http-exception' + +import { toQueryParams } from '../../utils/objectToQuery' +import type { GitHubErrorResponse, GitHubTokenResponse, GitHubUser, GitHubScope } from './types' + +type GithubAuthFlow = { + client_id: string + client_secret: string + scope?: GitHubScope[] + state: string + oauthApp: boolean + code: string | undefined +} +type Token = { + token: string + expires_in?: number +} +export class AuthFlow { + client_id: string + client_secret: string + scope: GitHubScope[] | undefined + state: string + oauthApp: boolean + code: string | undefined + token: Token | undefined + refresh_token: Token | undefined + user: Partial | undefined + granted_scopes: string[] | undefined + + constructor({ client_id, client_secret, scope, state, oauthApp, code }: GithubAuthFlow) { + this.client_id = client_id + this.client_secret = client_secret + this.scope = scope + this.state = state + this.oauthApp = oauthApp + this.code = code + this.token = undefined + this.refresh_token = undefined + this.user = undefined + this.granted_scopes = undefined + } + + redirect() { + const url = 'https://github.com/login/oauth/authorize?' + + if (this.oauthApp) { + const parsedScope = toQueryParams({ + scope: this.scope, + state: this.state, + }) + return `${url}${parsedScope}&client_id=${this.client_id}` + } + + return `${url}client_id=${this.client_id}` + } + + private async getTokenFromCode() { + const response = (await fetch('https://github.com/login/oauth/access_token', { + method: 'POST', + body: JSON.stringify({ + client_id: this.client_id, + client_secret: this.client_secret, + code: this.code, + }), + headers: { Accept: 'application/json', 'Content-Type': 'application/json' }, + }).then((res) => res.json())) as GitHubTokenResponse | GitHubErrorResponse + + if ('error_description' in response) + throw new HTTPException(400, { message: response.error_description }) + + if ('access_token' in response) { + this.token = { + token: response.access_token, + expires_in: response.expires_in, + } + this.granted_scopes = response.scope.split(',') + + if (response.refresh_token && response.refresh_token_expires_in) { + this.refresh_token = { + token: response.refresh_token, + expires_in: response.refresh_token_expires_in, + } + } + } + } + + async getUserData() { + if (!this.token?.token) await this.getTokenFromCode() + + const response = (await fetch('https://api.github.com/user', { + headers: { + Authorization: `Bearer ${this.token?.token}`, + Accept: 'application/json', + 'Content-Type': 'application/json', + 'User-Agent': 'Hono-Auth-App', + }, + }).then((res) => res.json())) as GitHubUser | GitHubErrorResponse + + if ('message' in response) throw new HTTPException(400, { message: response.message }) + + if ('id' in response) { + this.user = response + } + } +} diff --git a/packages/oauth-providers/src/providers/github/githubAuth.ts b/packages/oauth-providers/src/providers/github/githubAuth.ts new file mode 100644 index 00000000..fbae6ee4 --- /dev/null +++ b/packages/oauth-providers/src/providers/github/githubAuth.ts @@ -0,0 +1,57 @@ +import type { MiddlewareHandler } from 'hono' +import { getCookie, setCookie } from 'hono/cookie' +import { HTTPException } from 'hono/http-exception' + +import { getRandomState } from '../../utils/getRandomState' +import { AuthFlow } from './authFlow' +import type { GitHubScope } from './types' + +export function githubAuth(options: { + client_id?: string + client_secret?: string + scope?: GitHubScope[] + oauthApp?: boolean +}): MiddlewareHandler { + return async (c, next) => { + const newState = getRandomState() + // Create new Auth instance + const auth = new AuthFlow({ + client_id: options.client_id || (c.env?.GITHUB_ID as string), + client_secret: options.client_secret || (c.env?.GITHUB_SECRET as string), + scope: options.scope, + state: newState, + oauthApp: options.oauthApp || false, + code: c.req.query('code'), + }) + + // Avoid CSRF attack by checking state + if (c.req.url.includes('?')) { + const storedState = getCookie(c, 'state') + if (c.req.query('state') !== storedState) { + throw new HTTPException(401) + } + } + + // Redirect to login dialog + if (!auth.code) { + setCookie(c, 'state', newState, { + maxAge: 60 * 10, + httpOnly: true, + path: '/', + // secure: true, + }) + return c.redirect(auth.redirect()) + } + + // Retrieve user data from github + await auth.getUserData() + + // Set return info + c.set('token', auth.token) + c.set('refresh-token', auth.refresh_token) + c.set('user-github', auth.user) + c.set('granted-scopes', auth.granted_scopes) + + await next() + } +} diff --git a/packages/oauth-providers/src/providers/github/index.ts b/packages/oauth-providers/src/providers/github/index.ts new file mode 100644 index 00000000..da7ffdc0 --- /dev/null +++ b/packages/oauth-providers/src/providers/github/index.ts @@ -0,0 +1,10 @@ +import type { OAuthVariables } from '../../types' +import type { GitHubUser } from './types' +export { githubAuth } from './githubAuth' +export * from './types' + +declare module 'hono' { + interface ContextVariableMap extends OAuthVariables { + 'user-github': Partial | undefined + } +} diff --git a/packages/oauth-providers/src/providers/github/types.ts b/packages/oauth-providers/src/providers/github/types.ts new file mode 100644 index 00000000..a72fe28d --- /dev/null +++ b/packages/oauth-providers/src/providers/github/types.ts @@ -0,0 +1,97 @@ +export type GitHubScope = + | 'repo' + | 'repo:status' + | 'repo_deployment' + | 'public_repo' + | 'repo:invite' + | 'security_events' + | 'admin:repo_hook' + | 'write:repo_hook' + | 'read:repo_hook' + | 'admin:org' + | 'write:org' + | 'read:org' + | 'admin:public_key' + | 'write:public_key' + | 'read:public_key' + | 'admin:org_hook' + | 'gist' + | 'notifications' + | 'user' + | 'read:user' + | 'user:email' + | 'user:follow' + | 'project' + | 'read:project' + | 'delete_repo' + | 'write:packages' + | 'read:packages' + | 'delete:packages' + | 'admin:gpg_key' + | 'write:gpg_key' + | 'read:gpg_key' + | 'codespace' + | 'workflow' + +export type GitHubErrorResponse = { + error: string + error_description: string + message: string + documentation_url: string +} + +export type GitHubTokenResponse = { + access_token: string + expires_in?: number + refresh_token?: string + refresh_token_expires_in?: number + token_type: string + scope: string +} + +export type GitHubUser = { + login: string + id: number + node_id: string + avatar_url: string + gravatar_id: string + url: string + html_url: string + followers_url: string + following_url: string + gists_url: string + starred_url: string + subscriptions_url: string + organizations_url: string + repos_url: string + events_url: string + received_events_url: string + type: string + site_admin: boolean + name: string + company: string + blog: string + location: string + email: string | null + hireable: boolean | null + bio: string + twitter_username: string + public_repos: number + public_gists: number + followers: number + following: number + created_at: string + updated_at: string + private_gists: number + total_private_repos: number + owned_private_repos: number + disk_usage: number + collaborators: number + two_factor_authentication: boolean + plan: { + name: string + space: number + collaborators: number + private_repos: number + } +} diff --git a/packages/oauth-providers/src/providers/google/authFlow.ts b/packages/oauth-providers/src/providers/google/authFlow.ts new file mode 100644 index 00000000..a9644464 --- /dev/null +++ b/packages/oauth-providers/src/providers/google/authFlow.ts @@ -0,0 +1,119 @@ +import { HTTPException } from 'hono/http-exception' + +import type { Token } from '../../types' +import { toQueryParams } from '../../utils/objectToQuery' +import type { GoogleErrorResponse, GoogleTokenResponse, GoogleUser } from './types' + +type GoogleAuthFlow = { + client_id: string + client_secret: string + redirect_uri: string + code: string | undefined + token: Token | undefined + scope: string[] + state?: string + login_hint?: string + prompt?: 'none' | 'consent' | 'select_account' +} + +export class AuthFlow { + client_id: string + client_secret: string + redirect_uri: string + code: string | undefined + token: Token | undefined + scope: string[] + state: string | undefined + login_hint: string | undefined + prompt: 'none' | 'consent' | 'select_account' | undefined + user: Partial | undefined + granted_scopes: string[] | undefined + + constructor({ + client_id, + client_secret, + redirect_uri, + login_hint, + prompt, + scope, + state, + code, + token, + }: GoogleAuthFlow) { + this.client_id = client_id + this.client_secret = client_secret + this.redirect_uri = redirect_uri + this.login_hint = login_hint + this.prompt = prompt + this.scope = scope + this.state = state + this.code = code + this.token = token + this.user = undefined + this.granted_scopes = undefined + + if ( + this.client_id === undefined || + this.client_secret === undefined || + this.scope === undefined + ) { + throw new HTTPException(400, { + message: 'Required parameters were not found. Please provide them to proceed.', + }) + } + } + + redirect() { + const parsedOptions = toQueryParams({ + response_type: 'code', + redirect_uri: this.redirect_uri, + client_id: this.client_id, + include_granted_scopes: true, + scope: this.scope.join(' '), + state: this.state, + }) + return `https://accounts.google.com/o/oauth2/v2/auth?${parsedOptions}` + } + + async getTokenFromCode() { + const response = (await fetch('https://oauth2.googleapis.com/token', { + method: 'POST', + headers: { + 'content-type': 'application/json', + accept: 'application/json', + }, + body: JSON.stringify({ + clientId: this.client_id, + clientSecret: this.client_secret, + redirect_uri: this.redirect_uri, + code: this.code, + grant_type: 'authorization_code', + }), + }).then((res) => res.json())) as GoogleTokenResponse | GoogleErrorResponse + + if ('error' in response) throw new HTTPException(400, { message: response.error_description }) + + if ('access_token' in response) { + this.token = { + token: response.access_token, + expires_in: response.expires_in, + } + + this.granted_scopes = response.scope.split(' ') + } + } + + async getUserData() { + await this.getTokenFromCode() + + const response = (await fetch('https://www.googleapis.com/oauth2/v2/userinfo', { + headers: { + authorization: `Bearer ${this.token?.token}`, + }, + }).then((res) => res.json())) as GoogleUser | GoogleErrorResponse + + if ('error' in response) throw new HTTPException(400, { message: response.error?.message }) + + if ('id' in response) this.user = response + } +} diff --git a/packages/oauth-providers/src/providers/google/googleAuth.ts b/packages/oauth-providers/src/providers/google/googleAuth.ts new file mode 100644 index 00000000..43e5de0d --- /dev/null +++ b/packages/oauth-providers/src/providers/google/googleAuth.ts @@ -0,0 +1,62 @@ +import type { MiddlewareHandler } from 'hono' +import { getCookie, setCookie } from 'hono/cookie' +import { HTTPException } from 'hono/http-exception' + +import { getRandomState } from '../../utils/getRandomState' +import { AuthFlow } from './authFlow' + +export function googleAuth(options: { + scope: string[] + login_hint?: string + prompt?: 'none' | 'consent' | 'select_account' + client_id?: string + client_secret?: string +}): MiddlewareHandler { + return async (c, next) => { + const newState = getRandomState() + // Create new Auth instance + const auth = new AuthFlow({ + client_id: options.client_id || (c.env?.GOOGLE_ID as string), + client_secret: options.client_secret || (c.env?.GOOGLE_SECRET as string), + redirect_uri: c.req.url.split('?')[0], + login_hint: options.login_hint, + prompt: options.prompt, + scope: options.scope, + state: newState, + code: c.req.query('code'), + token: { + token: c.req.query('access_token') as string, + expires_in: Number(c.req.query('expires-in')) as number, + }, + }) + + // Avoid CSRF attack by checking state + if (c.req.url.includes('?')) { + const storedState = getCookie(c, 'state') + if (c.req.query('state') !== storedState) { + throw new HTTPException(401) + } + } + + // Redirect to login dialog + if (!auth.code) { + setCookie(c, 'state', newState, { + maxAge: 60 * 10, + httpOnly: true, + path: '/', + // secure: true, + }) + return c.redirect(auth.redirect()) + } + + // Retrieve user data from google + await auth.getUserData() + + // Set return info + c.set('token', auth.token) + c.set('user-google', auth.user) + c.set('granted-scopes', auth.granted_scopes) + + await next() + } +} diff --git a/packages/oauth-providers/src/providers/google/index.ts b/packages/oauth-providers/src/providers/google/index.ts new file mode 100644 index 00000000..b29775e2 --- /dev/null +++ b/packages/oauth-providers/src/providers/google/index.ts @@ -0,0 +1,11 @@ +export { googleAuth } from './googleAuth' +export { revokeToken } from './revokeToken' +export * from './types' +import type { OAuthVariables } from '../../types' +import type { GoogleUser } from './types' + +declare module 'hono' { + interface ContextVariableMap extends OAuthVariables { + 'user-google': Partial | undefined + } +} diff --git a/packages/oauth-providers/src/providers/google/revokeToken.ts b/packages/oauth-providers/src/providers/google/revokeToken.ts new file mode 100644 index 00000000..5ea8c495 --- /dev/null +++ b/packages/oauth-providers/src/providers/google/revokeToken.ts @@ -0,0 +1,8 @@ +export async function revokeToken(token: string) { + const response = await fetch(`https://oauth2.googleapis.com/revoke?token=${token}`, { + method: 'POST', + headers: { 'Content-type': 'application/x-www-form-urlencoded' }, + }) + + return response.status === 200 +} diff --git a/packages/oauth-providers/src/providers/google/types.ts b/packages/oauth-providers/src/providers/google/types.ts new file mode 100644 index 00000000..eafebf35 --- /dev/null +++ b/packages/oauth-providers/src/providers/google/types.ts @@ -0,0 +1,38 @@ +export type GoogleErrorResponse = { + error?: { + code: number + message: string + status: string + } + error_description: string +} + +export type GoogleTokenResponse = { + access_token: string + expires_in: number + scope: string + token_type: string + id_token: string +} + +export type GoogleTokenInfoResponse = { + issued_to: string + audience: string + user_id: string + scope: string + expires_in: number + email: string + verified_email: boolean + access_type: string +} + +export type GoogleUser = { + id: string + email: string + verified_email: boolean + name: string + given_name: string + family_name: string + picture: string + locale: string +} diff --git a/packages/oauth-providers/src/providers/linkedin/authFlow.ts b/packages/oauth-providers/src/providers/linkedin/authFlow.ts new file mode 100644 index 00000000..be211872 --- /dev/null +++ b/packages/oauth-providers/src/providers/linkedin/authFlow.ts @@ -0,0 +1,136 @@ +import { HTTPException } from 'hono/http-exception' + +import type { Token } from '../../types' +import { toQueryParams } from '../../utils/objectToQuery' +import type { + LinkedInErrorResponse, + LinkedInTokenResponse, + LinkedInUser, + LinkedInScope, +} from './types' + +export type LinkedInAuthFlow = { + client_id: string + client_secret: string + redirect_uri: string + scope: LinkedInScope[] | undefined + state: string + appAuth: boolean + code: string | undefined +} + +export class AuthFlow { + client_id: string + client_secret: string + redirect_uri: string + scope: LinkedInScope[] | undefined + state: string + code: string | undefined + token: Token | undefined + refresh_token: Token | undefined + user: Partial | undefined + granted_scopes: string[] | undefined + + constructor({ + client_id, + client_secret, + redirect_uri, + scope, + state, + appAuth, + code, + }: LinkedInAuthFlow) { + this.client_id = client_id + this.client_secret = client_secret + ;(this.redirect_uri = redirect_uri), (this.scope = scope) + this.state = state + this.code = appAuth ? '' : code + this.token = undefined + this.refresh_token = undefined + this.user = undefined + this.granted_scopes = undefined + } + + redirect() { + const params = toQueryParams({ + response_type: 'code', + client_id: this.client_id, + redirect_uri: this.redirect_uri, + scope: this.scope?.join(' ') || undefined, + state: this.state, + }) + + return `https://www.linkedin.com/oauth/v2/authorization?${params}` + } + + private async getTokenFromCode() { + const params = toQueryParams({ + grant_type: 'authorization_code', + code: this.code, + client_id: this.client_id, + client_secret: this.client_secret, + redirect_uri: this.redirect_uri, + }) + + const response = (await fetch(`https://www.linkedin.com/oauth/v2/accessToken?${params}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + }).then((res) => res.json())) as LinkedInTokenResponse | LinkedInErrorResponse + + if ('error' in response) throw new HTTPException(400, { message: response.error_description }) + + if ('access_token' in response) { + this.token = { + token: response.access_token, + expires_in: response.expires_in, + } + this.refresh_token = { + token: response.refresh_token, + expires_in: response.refresh_token_expires_in, + } + + this.granted_scopes = response.scope?.split(',') + } + } + + async getUserData() { + if (!this.token) { + await this.getTokenFromCode() + } + + const response = (await fetch('https://api.linkedin.com/v2/userinfo', { + headers: { + Authorization: `Bearer ${this.token?.token}`, + }, + }).then((res) => res.json())) as LinkedInUser | LinkedInErrorResponse + + if ('message' in response) throw new HTTPException(400, { message: response.message }) + + if ('sub' in response) this.user = response + } + + async getAppToken() { + const params = toQueryParams({ + grant_type: 'client_credentials', + client_id: this.client_id, + client_secret: this.client_secret, + }) + + const response = (await fetch(`https://www.linkedin.com/oauth/v2/accessToken?${params}`).then( + (res) => res.json() + )) as LinkedInTokenResponse | LinkedInErrorResponse + + if ('error' in response) throw new HTTPException(400, { message: response.error_description }) + + if ('access_token' in response) { + this.token = { + token: response.access_token, + expires_in: response.expires_in, + } + + this.granted_scopes = response.scope?.split(',') + } + } +} diff --git a/packages/oauth-providers/src/providers/linkedin/index.ts b/packages/oauth-providers/src/providers/linkedin/index.ts new file mode 100644 index 00000000..0b60932d --- /dev/null +++ b/packages/oauth-providers/src/providers/linkedin/index.ts @@ -0,0 +1,11 @@ +import type { OAuthVariables } from '../../types' +import type { LinkedInUser } from './types' +export { linkedinAuth } from './linkedinAuth' +export { refreshToken } from './refreshToken' +export * from './types' + +declare module 'hono' { + interface ContextVariableMap extends OAuthVariables { + 'user-linkedin': Partial | undefined + } +} diff --git a/packages/oauth-providers/src/providers/linkedin/linkedinAuth.ts b/packages/oauth-providers/src/providers/linkedin/linkedinAuth.ts new file mode 100644 index 00000000..204cc20f --- /dev/null +++ b/packages/oauth-providers/src/providers/linkedin/linkedinAuth.ts @@ -0,0 +1,61 @@ +import type { MiddlewareHandler } from 'hono' +import { getCookie, setCookie } from 'hono/cookie' +import { HTTPException } from 'hono/http-exception' + +import { getRandomState } from '../../utils/getRandomState' +import { AuthFlow } from './authFlow' +import type { LinkedInScope } from './types' + +export function linkedinAuth(options: { + client_id?: string + client_secret?: string + scope?: LinkedInScope[] + appAuth?: boolean +}): MiddlewareHandler { + return async (c, next) => { + const newState = getRandomState() + // Create new Auth instance + const auth = new AuthFlow({ + client_id: options.client_id || (c.env?.LINKEDIN_ID as string), + client_secret: options.client_secret || (c.env?.LINKEDIN_SECRET as string), + redirect_uri: c.req.url.split('?')[0], + scope: options.scope, + state: newState, + appAuth: options.appAuth || false, + code: c.req.query('code'), + }) + + // Avoid CSRF attack by checking state + if (c.req.url.includes('?')) { + const storedState = getCookie(c, 'state') + if (c.req.query('state') !== storedState) { + throw new HTTPException(401) + } + } + + // Redirect to login dialog + if (!auth.code && !options.appAuth) { + setCookie(c, 'state', newState, { + maxAge: 60 * 10, + httpOnly: true, + path: '/', + // secure: true, + }) + return c.redirect(auth.redirect()) + } + + if (options.appAuth) { + await auth.getAppToken() + } else { + await auth.getUserData() + } + + // Set return info + c.set('token', auth.token) + c.set('refresh-token', auth.refresh_token) + c.set('user-linkedin', auth.user) + c.set('granted-scopes', auth.granted_scopes) + + await next() + } +} diff --git a/packages/oauth-providers/src/providers/linkedin/refreshToken.ts b/packages/oauth-providers/src/providers/linkedin/refreshToken.ts new file mode 100644 index 00000000..68c96348 --- /dev/null +++ b/packages/oauth-providers/src/providers/linkedin/refreshToken.ts @@ -0,0 +1,28 @@ +import { HTTPException } from 'hono/http-exception' +import { toQueryParams } from '../../utils/objectToQuery' +import type { LinkedInErrorResponse, LinkedInTokenResponse } from './types' + +export async function refreshToken( + client_id: string, + client_secret: string, + refresh_token: string +): Promise { + const params = toQueryParams({ + grant_type: 'refresh_token', + refresh_token: refresh_token, + client_id: client_id, + client_secret: client_secret, + }) + + const response = (await fetch(`POST https://www.linkedin.com/oauth/v2/accessToken?${params}`, { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + }).then((res) => res.json())) as LinkedInTokenResponse | LinkedInErrorResponse + + if ('error' in response) { + throw new HTTPException(400, { message: response.error }) + } + + return response +} diff --git a/packages/oauth-providers/src/providers/linkedin/types.ts b/packages/oauth-providers/src/providers/linkedin/types.ts new file mode 100644 index 00000000..3c11831b --- /dev/null +++ b/packages/oauth-providers/src/providers/linkedin/types.ts @@ -0,0 +1,51 @@ +export type LinkedInScope = + | 'profile' + | 'email' + | 'openid' + | 'w_member_social' + | 'rw_organization_admin' + | 'r_organization_admin' + | 'w_organization_social' + | 'r_organization_social' + | 'w_member_social' + | 'rw_ads' + | 'r_ads' + | 'r_ads_reporting' + | 'r_1st_connections_size' + | 'r_basicprofile' + | 'r_marketing_leadgen_automation' + | 'rw_dmp_segments' + | 'r_sales_nav_analytics' + | 'r_sales_nav_display' + | 'r_sales_nav_validation' + | 'r_sales_nav_profiles' + | 'r_compliance' + | 'w_compliance' + +export type LinkedInErrorResponse = { + error: string + error_description: string + message: string +} + +export type LinkedInTokenResponse = { + access_token: string + expires_in: number + refresh_token: string + refresh_token_expires_in: number + scope?: string +} + +export type LinkedInUser = { + sub: string + email_verified: boolean + name: string + locale: { + country: string + language: string + } + given_name: string + family_name: string + email: string + picture: string +} diff --git a/packages/oauth-providers/src/types.ts b/packages/oauth-providers/src/types.ts new file mode 100644 index 00000000..47f2d9b0 --- /dev/null +++ b/packages/oauth-providers/src/types.ts @@ -0,0 +1,10 @@ +export type OAuthVariables = { + token: Token | undefined + 'refresh-token': Token | undefined + 'granted-scopes': string[] | undefined +} + +export type Token = { + token: string + expires_in: number +} diff --git a/packages/oauth-providers/src/utils/getRandomState.ts b/packages/oauth-providers/src/utils/getRandomState.ts new file mode 100644 index 00000000..691b90bb --- /dev/null +++ b/packages/oauth-providers/src/utils/getRandomState.ts @@ -0,0 +1,7 @@ +const rand = () => { + return Math.random().toString(36).substr(2) +} + +export function getRandomState() { + return `${rand()}-${rand()}-${rand()}` +} diff --git a/packages/oauth-providers/src/utils/objectToQuery.ts b/packages/oauth-providers/src/utils/objectToQuery.ts new file mode 100644 index 00000000..390d68a0 --- /dev/null +++ b/packages/oauth-providers/src/utils/objectToQuery.ts @@ -0,0 +1,12 @@ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function toQueryParams(params: { [key: string]: any }): string { + const elements = Object.keys(params) + + elements.forEach((element) => { + if (params[element] === undefined) { + delete params[element] + } + }) + + return new URLSearchParams(params).toString() +} diff --git a/packages/oauth-providers/test/handlers.ts b/packages/oauth-providers/test/handlers.ts new file mode 100644 index 00000000..4312b694 --- /dev/null +++ b/packages/oauth-providers/test/handlers.ts @@ -0,0 +1,264 @@ +import type { DefaultBodyType, StrictResponse } from 'msw' +import { HttpResponse, http } from 'msw' + +import type { + FacebookErrorResponse, + FacebookTokenResponse, + FacebookUser, +} from '../src/providers/facebook' +import type { GitHubErrorResponse, GitHubTokenResponse } from '../src/providers/github' +import type { + GoogleErrorResponse, + GoogleTokenResponse, + GoogleUser, +} from '../src/providers/google/types' +import type { LinkedInErrorResponse, LinkedInTokenResponse } from '../src/providers/linkedin' + +export const handlers = [ + // Google + http.post( + 'https://oauth2.googleapis.com/token', + async ({ + request, + }): Promise | GoogleErrorResponse>> => { + const body = (await request.json()) as Promise & { code: string } + if (body.code === dummyCode) { + return HttpResponse.json(dummyToken) + } + return HttpResponse.json(googleCodeError) + } + ), + http.get( + 'https://www.googleapis.com/oauth2/v2/userinfo', + async ({ request }): Promise | GoogleErrorResponse>> => { + const authorization = request.headers.get('authorization') + if (authorization === `Bearer ${dummyToken.access_token}`) { + return HttpResponse.json(googleUser) + } + return HttpResponse.json(googleTokenError) + } + ), + http.get('https://www.googleapis.com/oauth2/v1/tokeninfo', () => + HttpResponse.json(googleTokenInfo) + ), + // Facebook + http.get( + 'https://graph.facebook.com/v18.0/oauth/access_token', + async ({ + request, + }): Promise | FacebookErrorResponse>> => { + const code = new URLSearchParams(request.url).get('code') + if (dummyCode === code) { + return HttpResponse.json(dummyToken) + } + return HttpResponse.json(facebookCodeError) + } + ), + http.get('https://graph.facebook.com/v18.0/me', () => HttpResponse.json(facebookBasicInfo)), + http.get( + 'https://graph.facebook.com/1abc345-75uyut', + async ({ request }): Promise | FacebookErrorResponse>> => { + const token = new URLSearchParams(request.url).get('access_token') + if (token === dummyToken.access_token) { + return HttpResponse.json(facebookUser) + } + return HttpResponse.json(facebookTokenError) + } + ), + // Github + http.post( + 'https://github.com/login/oauth/access_token', + async ({ + request, + }): Promise>> => { + const body = (await request.json()) as Promise & { code: string } + if (body.code === dummyCode) { + return HttpResponse.json(githubToken) + } + return HttpResponse.json(githubCodeError) + } + ), + http.get('https://api.github.com/user', () => HttpResponse.json(githubUser)), + // LinkedIn + http.post( + 'https://www.linkedin.com/oauth/v2/accessToken', + async ({ + request, + }): Promise | LinkedInErrorResponse>> => { + const code = new URLSearchParams(request.url).get('code') + if (code === dummyCode) { + return HttpResponse.json(linkedInToken) + } + return HttpResponse.json(linkedInCodeError) + } + ), + http.get('https://api.linkedin.com/v2/userinfo', () => HttpResponse.json(linkedInUser)), +] + +export const dummyCode = '4/0AfJohXl9tS46EmTA6u9x3pJQiyCNyahx4DLJaeJelzJ0E5KkT4qJmCtjq9n3FxBvO40ofg' +export const dummyToken = { + access_token: '15d42a4d-1948-4de4-ba78-b8a893feaf45', + expires_in: 60000, + scope: 'openid email profile', +} + +export const googleUser = { + id: '1abc345-75uyut', + email: 'example@email.com', + verified_email: true, + name: 'Carlos Aldazosa', + given_name: 'Carlos', + family_name: 'Aldazosa', + picture: 'https://www.severnedgevets.co.uk/sites/default/files/guides/kitten.png', + locale: 'es-419', +} +export const googleCodeError = { + error: { + code: 401, + message: 'Invalid code.', + status: '401', + error: 'code_invalid', + }, + error_description: 'Invalid code.', +} +export const googleTokenError = { + error: { + code: 401, + message: 'Invalid token.', + status: '401', + error: 'token_invalid', + }, + error_description: 'Invalid token.', +} +const googleTokenInfo = { + issued_to: 'hyr97.457_e5gh4', + audience: 'hyr97.457_e5gh4google.com', + user_id: 'dummy-id', + scope: 'openid email profile', + expires_in: 60000, + email: 'example@email.com', + verified_email: true, + access_type: 'user', +} + +export const facebookUser = { + id: '1abc345-75uyut', + name: 'Carlos Aldazosa', + email: 'example@email.com', + picture: { + data: { + height: 50, + width: 50, + is_silhouette: true, + url: 'https://www.severnedgevets.co.uk/sites/default/files/guides/kitten.png', + }, + }, + first_name: 'Carlos', + last_name: 'Aldazosa', + short_name: 'Carlos', +} +export const facebookCodeError = { + error: { + message: 'Invalid Code.', + type: 'Invalid', + code: 401, + fbtrace_id: 'jujublabla', + }, +} +export const facebookTokenError = { + error: { + message: 'Invalid Token.', + type: 'Invalid', + code: 401, + fbtrace_id: 'jujublabla', + }, +} +const facebookBasicInfo = { + id: '1abc345-75uyut', + name: 'Carlos Aldazosa', +} + +export const githubToken = { + access_token: '15d42a4d-1948-4de4-ba78-b8a893feaf45', + expires_in: 60000, + scope: 'public_repo,user', + refresh_token: 't4589fh-9gj3g93-34f5t64n', + refresh_token_expires_in: 6000000, + token_type: 'bearer', +} +export const githubUser = { + login: 'monoald', + id: 9876543210, + node_id: 'HFGJ$FEF598', + avatar_url: 'https://avatars.githubusercontent.com/u/userid', + gravatar_id: '', + url: 'https://api.github.com/users', + html_url: 'https://github.com/monoald', + followers_url: 'https://api.github.com/users/user/followers', + following_url: 'https://api.github.com/users/user/following{/other_user}', + gists_url: 'https://api.github.com/users/user/gists{/gist_id}', + starred_url: 'https://api.github.com/users/user/starred{/owner}{/repo}', + subscriptions_url: 'https://api.github.com/users/user/subscriptions', + organizations_url: 'https://api.github.com/users/user/orgs', + repos_url: 'https://api.github.com/users/user/repos', + events_url: 'https://api.github.com/users/user/events{/privacy}', + received_events_url: 'https://api.github.com/users/user/received_events', + type: 'User', + site_admin: false, + name: 'Carlos Aldazosa', + company: '@rvesoftware', + blog: 'https://monoald.github.io/', + location: 'Knowhere', + email: null, + hireable: null, + bio: 'BIO description', + twitter_username: 'monoald', + public_repos: 0, + public_gists: 0, + followers: 0, + following: 0, + created_at: '2023-11-07T13:11:55Z', + updated_at: '2023-11-07T13:11:56Z', + private_gists: 0, + total_private_repos: 0, + owned_private_repos: 0, + disk_usage: 100000, + collaborators: 0, + two_factor_authentication: false, + plan: { + name: 'free', + space: 100000000, + collaborators: 0, + private_repos: 10000, + }, +} +export const githubCodeError = { + error_description: 'Invalid Code.', +} + +export const linkedInToken = { + access_token: '15d42a4d-1948-4de4-ba78-b8a893feaf45', + expires_in: 60000, + scope: 'email,openid,profile', + refresh_token: 't4589fh-9gj3g93-34f5t64n', + refresh_token_expires_in: 6000000, + token_type: 'bearer', +} +export const linkedInCodeError = { + error_description: 'The Code you send is invalid.', + error: 'The Code you send is invalid.', + message: 'The Code you send is invalid.', +} +export const linkedInUser = { + sub: '452FET361006', + email_verified: true, + name: 'Carlos Aldazosa', + locale: { + country: 'US', + language: 'en', + }, + given_name: 'Carlos', + family_name: 'Aldazosa', + email: 'example@email.com', + picture: 'https://www.severnedgevets.co.uk/sites/default/files/guides/kitten.png', +} diff --git a/packages/oauth-providers/test/index.test.ts b/packages/oauth-providers/test/index.test.ts new file mode 100644 index 00000000..0f77dc1c --- /dev/null +++ b/packages/oauth-providers/test/index.test.ts @@ -0,0 +1,361 @@ +import { Hono } from 'hono' +import { setupServer } from 'msw/node' +import { facebookAuth } from '../src/providers/facebook' +import type { FacebookUser } from '../src/providers/facebook' +import { githubAuth } from '../src/providers/github' +import type { GitHubUser } from '../src/providers/github' +import { googleAuth } from '../src/providers/google' +import type { GoogleUser } from '../src/providers/google' +import { linkedinAuth } from '../src/providers/linkedin' +import type { LinkedInUser } from '../src/providers/linkedin' +import type { Token } from '../src/types' +import { + dummyToken, + googleUser, + handlers, + facebookUser, + githubUser, + dummyCode, + googleCodeError, + facebookCodeError, + githubToken, + githubCodeError, + linkedInCodeError, + linkedInUser, + linkedInToken, +} from './handlers' + +const server = setupServer(...handlers) +server.listen() + +const client_id = '1jsdsldjkssd-4343dsasdsd34ghhn4-dummyid' +const client_secret = 'SDJS943hS_jj45dummysecret' + +describe('OAuth Middleware', () => { + const app = new Hono() + + app.use( + '/google', + googleAuth({ + client_id, + client_secret, + scope: ['openid', 'email', 'profile'], + }) + ) + app.get('/google', (c) => { + const user = c.get('user-google') + const token = c.get('token') + const grantedScopes = c.get('granted-scopes') + + return c.json({ + user, + token, + grantedScopes, + }) + }) + + app.use( + '/facebook', + facebookAuth({ + client_id, + client_secret, + scope: ['email', 'public_profile'], + fields: [ + 'email', + 'id', + 'first_name', + 'last_name', + 'middle_name', + 'name', + 'picture', + 'short_name', + ], + }) + ) + app.get('/facebook', (c) => { + const user = c.get('user-facebook') + const token = c.get('token') + const grantedScopes = c.get('granted-scopes') + + return c.json({ + user, + token, + grantedScopes, + }) + }) + + app.use( + '/github/app', + githubAuth({ + client_id, + client_secret, + }) + ) + app.get('/github/app', (c) => { + const token = c.get('token') + const refreshToken = c.get('refresh-token') + const user = c.get('user-github') + const grantedScopes = c.get('granted-scopes') + + return c.json({ + token, + refreshToken, + user, + grantedScopes, + }) + }) + app.use( + '/github/oauth-app', + githubAuth({ + client_id, + client_secret, + scope: ['public_repo', 'read:user', 'user', 'user:email', 'user:follow'], + oauthApp: true, + }) + ) + app.get('/github/oauth-app', (c) => { + const token = c.get('token') + const user = c.get('user-github') + const grantedScopes = c.get('granted-scopes') + + return c.json({ + user, + token, + grantedScopes, + }) + }) + + app.use( + 'linkedin', + linkedinAuth({ + client_id, + client_secret, + scope: ['email', 'openid', 'profile'], + }) + ) + app.get('linkedin', (c) => { + const token = c.get('token') + const refreshToken = c.get('refresh-token') + const user = c.get('user-linkedin') + const grantedScopes = c.get('granted-scopes') + + return c.json({ + token, + refreshToken, + grantedScopes, + user, + }) + }) + + beforeAll(() => { + server.listen() + }) + afterEach(() => { + server.resetHandlers() + }) + afterAll(() => { + server.close() + }) + + describe('googleAuth middleware', () => { + it('Should redirect', async () => { + const res = await app.request('/google') + + expect(res).not.toBeNull() + expect(res.status).toBe(302) + }) + + it('Prevent CSRF attack', async () => { + const res = await app.request(`/google?code=${dummyCode}&state=malware-state`) + + expect(res).not.toBeNull() + expect(res.status).toBe(401) + }) + + it('Should throw error for invalide code', async () => { + const res = await app.request('/google?code=9348ffdsd-sdsdbad-code') + + expect(res).not.toBeNull() + expect(res.status).toBe(400) + expect(await res.text()).toBe(googleCodeError.error.message) + }) + + it('Should work with received code', async () => { + const res = await app.request(`/google?code=${dummyCode}`) + const response = (await res.json()) as { + token: Token + user: GoogleUser + grantedScopes: string[] + } + + expect(res).not.toBeNull() + expect(res.status).toBe(200) + expect(response.user).toEqual(googleUser) + expect(response.grantedScopes).toEqual(dummyToken.scope.split(' ')) + expect(response.token).toEqual({ + token: dummyToken.access_token, + expires_in: dummyToken.expires_in, + }) + }) + }) + + describe('facebookAuth middleware', () => { + it('Should redirect', async () => { + const res = await app.request('/facebook') + + expect(res).not.toBeNull() + expect(res.status).toBe(302) + }) + + it('Prevent CSRF attack', async () => { + const res = await app.request(`/facebook?code=${dummyCode}&state=malware-state`) + expect(res).not.toBeNull() + expect(res.status).toBe(401) + }) + + it('Should throw error for invalid code', async () => { + const res = await app.request('/facebook?code=9348ffdsd-sdsdbad-code') + + expect(res).not.toBeNull() + expect(res.status).toBe(400) + expect(await res.text()).toBe(facebookCodeError.error.message) + }) + + it('Should work with received code', async () => { + const res = await app.request( + `/facebook?code=${dummyCode}&granted_scopes=email%2Cpublic_profile` + ) + const response = (await res.json()) as { + token: Token + user: FacebookUser + grantedScopes: string[] + } + + expect(res).not.toBeNull() + expect(res.status).toBe(200) + expect(response.user).toEqual(facebookUser) + expect(response.grantedScopes).toEqual(['email', 'public_profile']) + expect(response.token).toEqual({ + token: dummyToken.access_token, + expires_in: dummyToken.expires_in, + }) + }) + }) + + describe('githubAuth middleware', () => { + describe('Github with Github App', () => { + it('Should redirect', async () => { + const res = await app.request('/github/app') + + expect(res).not.toBeNull() + expect(res.status).toBe(302) + }) + + it('Should throw error for invalide code', async () => { + const res = await app.request('/github/app?code=9348ffdsd-sdsdbad-code') + + expect(res).not.toBeNull() + expect(res.status).toBe(400) + expect(await res.text()).toBe(githubCodeError.error_description) + }) + + it('Should work with received code', async () => { + const res = await app.request(`/github/app?code=${dummyCode}`) + const response = (await res.json()) as { + token: Token + refreshToken: Token + user: GitHubUser + grantedScopes: string[] + } + + expect(res).not.toBeNull() + expect(res.status).toBe(200) + expect(response.user).toEqual(githubUser) + expect(response.grantedScopes).toEqual(['public_repo', 'user']) + expect(response.token).toEqual({ + token: githubToken.access_token, + expires_in: githubToken.expires_in, + }) + expect(response.refreshToken).toEqual({ + token: githubToken.refresh_token, + expires_in: githubToken.refresh_token_expires_in, + }) + }) + }) + + describe('Github with OAuth App', () => { + it('Should redirect', async () => { + const res = await app.request('/github/oauth-app') + + expect(res).not.toBeNull() + expect(res.status).toBe(302) + }) + + it('Should throw error for invalide code', async () => { + const res = await app.request('/github/oauth-app?code=9348ffdsd-sdsdbad-code') + + expect(res).not.toBeNull() + expect(res.status).toBe(400) + expect(await res.text()).toBe(githubCodeError.error_description) + }) + + it('Should work with received code', async () => { + const res = await app.request(`/github/oauth-app?code=${dummyCode}`) + const response = (await res.json()) as { + token: Token + user: GitHubUser + grantedScopes: string[] + } + + expect(res).not.toBeNull() + expect(res.status).toBe(200) + expect(response.user).toEqual(githubUser) + expect(response.grantedScopes).toEqual(['public_repo', 'user']) + expect(response.token).toEqual({ + token: githubToken.access_token, + expires_in: githubToken.expires_in, + }) + }) + }) + }) + + describe('linkedinAuth middleware', () => { + it('Should redirect', async () => { + const res = await app.request('/linkedin') + + expect(res).not.toBeNull() + expect(res.status).toBe(302) + }) + + it('Should throw error for invalide code', async () => { + const res = await app.request('/linkedin?code=9348ffdsd-sdsdbad-code') + + expect(res).not.toBeNull() + expect(res.status).toBe(400) + expect(await res.text()).toBe(linkedInCodeError.error) + }) + + it('Should work with received code', async () => { + const res = await app.request(`/linkedin?code=${dummyCode}`) + const response = (await res.json()) as { + token: Token + refreshToken: Token + user: LinkedInUser + grantedScopes: string[] + } + + expect(res).not.toBeNull() + expect(res.status).toBe(200) + expect(response.user).toEqual(linkedInUser) + expect(response.grantedScopes).toEqual(['email', 'openid', 'profile']) + expect(response.token).toEqual({ + token: linkedInToken.access_token, + expires_in: linkedInToken.expires_in, + }) + expect(response.refreshToken).toEqual({ + token: linkedInToken.refresh_token, + expires_in: linkedInToken.refresh_token_expires_in, + }) + }) + }) +}) diff --git a/packages/oauth-providers/tsconfig.json b/packages/oauth-providers/tsconfig.json new file mode 100644 index 00000000..acfcd843 --- /dev/null +++ b/packages/oauth-providers/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + }, + "include": [ + "src/**/*.ts" + ], +} \ No newline at end of file diff --git a/packages/oauth-providers/tsup.config.ts b/packages/oauth-providers/tsup.config.ts new file mode 100644 index 00000000..146d6e33 --- /dev/null +++ b/packages/oauth-providers/tsup.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from 'tsup' + +export default defineConfig({ + entry: ['src/index.ts', 'src/providers/**/index.ts', 'src/providers/**/types.ts'], + format: ['esm', 'cjs'], + dts: true, + splitting: false, + clean: true, +}) diff --git a/yarn.lock b/yarn.lock index 21bd2fe5..1dc603b5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -343,6 +343,27 @@ dependencies: csstype "^3.1.2" +"@bundled-es-modules/cookie@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@bundled-es-modules/cookie/-/cookie-2.0.0.tgz#c3b82703969a61cf6a46e959a012b2c257f6b164" + integrity sha512-Or6YHg/kamKHpxULAdSqhGqnWFneIXu1NKvvfBBzKGwpVsYuFIQ5aBPHDnnoR3ghW1nvSkALd+EF9iMtY7Vjxw== + dependencies: + cookie "^0.5.0" + +"@bundled-es-modules/js-levenshtein@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@bundled-es-modules/js-levenshtein/-/js-levenshtein-2.0.1.tgz#b02bbbd546358ab77080a430f0911cfc2b3779c4" + integrity sha512-DERMS3yfbAljKsQc0U2wcqGKUWpdFjwqWuoMugEJlqBnKO180/n+4SR/J8MRDt1AN48X1ovgoD9KrdVXcaa3Rg== + dependencies: + js-levenshtein "^1.1.6" + +"@bundled-es-modules/statuses@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@bundled-es-modules/statuses/-/statuses-1.0.1.tgz#761d10f44e51a94902c4da48675b71a76cc98872" + integrity sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg== + dependencies: + statuses "^2.0.1" + "@changesets/apply-release-plan@^6.1.3": version "6.1.3" resolved "https://registry.yarnpkg.com/@changesets/apply-release-plan/-/apply-release-plan-6.1.3.tgz#3bcc0bd57ba00d50d20df7d0141f1a9b2134eaf7" @@ -655,6 +676,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.5.tgz#276c5f99604054d3dbb733577e09adae944baa90" integrity sha512-5d1OkoJxnYQfmC+Zd8NBFjkhyCNYwM4n9ODrycTFY6Jk1IGiZ+tjVJDDSwDt77nK+tfpGP4T50iMtVi4dEGzhQ== +"@esbuild/android-arm64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.6.tgz#13d98a34bbbde4237867cc232307a20ded139b6f" + integrity sha512-KQ/hbe9SJvIJ4sR+2PcZ41IBV+LPJyYp6V1K1P1xcMRup9iYsBoQn4MzE3mhMLOld27Au2eDcLlIREeKGUXpHQ== + "@esbuild/android-arm@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682" @@ -665,6 +691,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.5.tgz#4a3cbf14758166abaae8ba9c01a80e68342a4eec" integrity sha512-bhvbzWFF3CwMs5tbjf3ObfGqbl/17ict2/uwOSfr3wmxDE6VdS2GqY/FuzIPe0q0bdhj65zQsvqfArI9MY6+AA== +"@esbuild/android-arm@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.6.tgz#68898d949672c56f10451f540fd92301dc713fb3" + integrity sha512-muPzBqXJKCbMYoNbb1JpZh/ynl0xS6/+pLjrofcR3Nad82SbsCogYzUE6Aq9QT3cLP0jR/IVK/NHC9b90mSHtg== + "@esbuild/android-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2" @@ -675,6 +706,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.5.tgz#21a3d11cd4613d2d3c5ccb9e746c254eb9265b0a" integrity sha512-9t+28jHGL7uBdkBjL90QFxe7DVA+KGqWlHCF8ChTKyaKO//VLuoBricQCgwhOjA1/qOczsw843Fy4cbs4H3DVA== +"@esbuild/android-x64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.6.tgz#51a0ab83680dedc6dd1ae26133def26b178ed3a1" + integrity sha512-VVJVZQ7p5BBOKoNxd0Ly3xUM78Y4DyOoFKdkdAe2m11jbh0LEU4bPles4e/72EMl4tapko8o915UalN/5zhspg== + "@esbuild/darwin-arm64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1" @@ -685,6 +721,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.5.tgz#714cb839f467d6a67b151ee8255886498e2b9bf6" integrity sha512-mvXGcKqqIqyKoxq26qEDPHJuBYUA5KizJncKOAf9eJQez+L9O+KfvNFu6nl7SCZ/gFb2QPaRqqmG0doSWlgkqw== +"@esbuild/darwin-arm64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.6.tgz#2883f14197111febb118c0463c080930a30883e5" + integrity sha512-91LoRp/uZAKx6ESNspL3I46ypwzdqyDLXZH7x2QYCLgtnaU08+AXEbabY2yExIz03/am0DivsTtbdxzGejfXpA== + "@esbuild/darwin-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d" @@ -695,6 +736,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.5.tgz#2c553e97a6d2b4ae76a884e35e6cbab85a990bbf" integrity sha512-Ly8cn6fGLNet19s0X4unjcniX24I0RqjPv+kurpXabZYSXGM4Pwpmf85WHJN3lAgB8GSth7s5A0r856S+4DyiA== +"@esbuild/darwin-x64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.6.tgz#400bf20f9a35a7d68a17f5898c0f9ecb099f062b" + integrity sha512-QCGHw770ubjBU1J3ZkFJh671MFajGTYMZumPs9E/rqU52md6lIil97BR0CbPq6U+vTh3xnTNDHKRdR8ggHnmxQ== + "@esbuild/freebsd-arm64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54" @@ -705,6 +751,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.5.tgz#d554f556718adb31917a0da24277bf84b6ee87f3" integrity sha512-GGDNnPWTmWE+DMchq1W8Sd0mUkL+APvJg3b11klSGUDvRXh70JqLAO56tubmq1s2cgpVCSKYywEiKBfju8JztQ== +"@esbuild/freebsd-arm64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.6.tgz#8af07bd848afa2470b8a2339b203ce29a721152b" + integrity sha512-J53d0jGsDcLzWk9d9SPmlyF+wzVxjXpOH7jVW5ae7PvrDst4kiAz6sX+E8btz0GB6oH12zC+aHRD945jdjF2Vg== + "@esbuild/freebsd-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e" @@ -715,6 +766,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.5.tgz#288f7358a3bb15d99e73c65c9adaa3dabb497432" integrity sha512-1CCwDHnSSoA0HNwdfoNY0jLfJpd7ygaLAp5EHFos3VWJCRX9DMwWODf96s9TSse39Br7oOTLryRVmBoFwXbuuQ== +"@esbuild/freebsd-x64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.6.tgz#ae0230860e27df204a616671e028ff8fdffa009a" + integrity sha512-hn9qvkjHSIB5Z9JgCCjED6YYVGCNpqB7dEGavBdG6EjBD8S/UcNUIlGcB35NCkMETkdYwfZSvD9VoDJX6VeUVA== + "@esbuild/linux-arm64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0" @@ -725,6 +781,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.5.tgz#95933ae86325c93cb6b5e8333d22120ecfdc901b" integrity sha512-o3vYippBmSrjjQUCEEiTZ2l+4yC0pVJD/Dl57WfPwwlvFkrxoSO7rmBZFii6kQB3Wrn/6GwJUPLU5t52eq2meA== +"@esbuild/linux-arm64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.6.tgz#3042bc423a978deab44a72244b863f743fd9fda1" + integrity sha512-HQCOrk9XlH3KngASLaBfHpcoYEGUt829A9MyxaI8RMkfRA8SakG6YQEITAuwmtzFdEu5GU4eyhKcpv27dFaOBg== + "@esbuild/linux-arm@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0" @@ -735,6 +796,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.5.tgz#0acef93aa3e0579e46d33b666627bddb06636664" integrity sha512-lrWXLY/vJBzCPC51QN0HM71uWgIEpGSjSZZADQhq7DKhPcI6NH1IdzjfHkDQws2oNpJKpR13kv7/pFHBbDQDwQ== +"@esbuild/linux-arm@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.6.tgz#50a537de609315979509120b0181882978294db1" + integrity sha512-G8IR5zFgpXad/Zp7gr7ZyTKyqZuThU6z1JjmRyN1vSF8j0bOlGzUwFSMTbctLAdd7QHpeyu0cRiuKrqK1ZTwvQ== + "@esbuild/linux-ia32@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7" @@ -745,6 +811,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.5.tgz#b6e5c9e80b42131cbd6b1ddaa48c92835f1ed67f" integrity sha512-MkjHXS03AXAkNp1KKkhSKPOCYztRtK+KXDNkBa6P78F8Bw0ynknCSClO/ztGszILZtyO/lVKpa7MolbBZ6oJtQ== +"@esbuild/linux-ia32@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.6.tgz#f99c48b597facf9cbf8e1a2522ce379b2ad7b0c4" + integrity sha512-22eOR08zL/OXkmEhxOfshfOGo8P69k8oKHkwkDrUlcB12S/sw/+COM4PhAPT0cAYW/gpqY2uXp3TpjQVJitz7w== + "@esbuild/linux-loong64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d" @@ -755,6 +826,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.5.tgz#e5f0cf95a180158b01ff5f417da796a1c09dfbea" integrity sha512-42GwZMm5oYOD/JHqHska3Jg0r+XFb/fdZRX+WjADm3nLWLcIsN27YKtqxzQmGNJgu0AyXg4HtcSK9HuOk3v1Dw== +"@esbuild/linux-loong64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.6.tgz#9fe79be31ce305564aa62da190f38e199d6d26b7" + integrity sha512-82RvaYAh/SUJyjWA8jDpyZCHQjmEggL//sC7F3VKYcBMumQjUL3C5WDl/tJpEiKtt7XrWmgjaLkrk205zfvwTA== + "@esbuild/linux-mips64el@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231" @@ -765,6 +841,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.5.tgz#ae36fb86c7d5f641f3a0c8472e83dcb6ea36a408" integrity sha512-kcjndCSMitUuPJobWCnwQ9lLjiLZUR3QLQmlgaBfMX23UEa7ZOrtufnRds+6WZtIS9HdTXqND4yH8NLoVVIkcg== +"@esbuild/linux-mips64el@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.6.tgz#5a922dad90fc8a83fd0631c136b46128153ffb6f" + integrity sha512-8tvnwyYJpR618vboIv2l8tK2SuK/RqUIGMfMENkeDGo3hsEIrpGldMGYFcWxWeEILe5Fi72zoXLmhZ7PR23oQA== + "@esbuild/linux-ppc64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb" @@ -775,6 +856,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.5.tgz#7960cb1666f0340ddd9eef7b26dcea3835d472d0" integrity sha512-yJAxJfHVm0ZbsiljbtFFP1BQKLc8kUF6+17tjQ78QjqjAQDnhULWiTA6u0FCDmYT1oOKS9PzZ2z0aBI+Mcyj7Q== +"@esbuild/linux-ppc64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.6.tgz#a7fccf924824999b301546843adb4f51051965e8" + integrity sha512-Qt+D7xiPajxVNk5tQiEJwhmarNnLPdjXAoA5uWMpbfStZB0+YU6a3CtbWYSy+sgAsnyx4IGZjWsTzBzrvg/fMA== + "@esbuild/linux-riscv64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6" @@ -785,6 +871,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.5.tgz#32207df26af60a3a9feea1783fc21b9817bade19" integrity sha512-5u8cIR/t3gaD6ad3wNt1MNRstAZO+aNyBxu2We8X31bA8XUNyamTVQwLDA1SLoPCUehNCymhBhK3Qim1433Zag== +"@esbuild/linux-riscv64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.6.tgz#41d2db11550662d6c03902d9d8d26b0ed5bb8d55" + integrity sha512-lxRdk0iJ9CWYDH1Wpnnnc640ajF4RmQ+w6oHFZmAIYu577meE9Ka/DCtpOrwr9McMY11ocbp4jirgGgCi7Ls/g== + "@esbuild/linux-s390x@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071" @@ -795,6 +886,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.5.tgz#b38d5681db89a3723862dfa792812397b1510a7d" integrity sha512-Z6JrMyEw/EmZBD/OFEFpb+gao9xJ59ATsoTNlj39jVBbXqoZm4Xntu6wVmGPB/OATi1uk/DB+yeDPv2E8PqZGw== +"@esbuild/linux-s390x@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.6.tgz#d7a843a2620e73c5c9d65c482e2fbddc7e0f7753" + integrity sha512-MopyYV39vnfuykHanRWHGRcRC3AwU7b0QY4TI8ISLfAGfK+tMkXyFuyT1epw/lM0pflQlS53JoD22yN83DHZgA== + "@esbuild/linux-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338" @@ -805,6 +901,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.5.tgz#46feba2ad041a241379d150f415b472fe3885075" integrity sha512-psagl+2RlK1z8zWZOmVdImisMtrUxvwereIdyJTmtmHahJTKb64pAcqoPlx6CewPdvGvUKe2Jw+0Z/0qhSbG1A== +"@esbuild/linux-x64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.6.tgz#d3f20f0c2bdaa1b9ed1c0df7db034771e7aa5234" + integrity sha512-UWcieaBzsN8WYbzFF5Jq7QULETPcQvlX7KL4xWGIB54OknXJjBO37sPqk7N82WU13JGWvmDzFBi1weVBajPovg== + "@esbuild/netbsd-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1" @@ -815,6 +916,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.5.tgz#3b5c1fb068f26bfc681d31f682adf1bea4ef0702" integrity sha512-kL2l+xScnAy/E/3119OggX8SrWyBEcqAh8aOY1gr4gPvw76la2GlD4Ymf832UCVbmuWeTf2adkZDK+h0Z/fB4g== +"@esbuild/netbsd-x64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.6.tgz#6108d7270599ee37cd57bb14e4516a83541885d5" + integrity sha512-EpWiLX0fzvZn1wxtLxZrEW+oQED9Pwpnh+w4Ffv8ZLuMhUoqR9q9rL4+qHW8F4Mg5oQEKxAoT0G+8JYNqCiR6g== + "@esbuild/openbsd-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae" @@ -825,6 +931,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.5.tgz#ca6830316ca68056c5c88a875f103ad3235e00db" integrity sha512-sPOfhtzFufQfTBgRnE1DIJjzsXukKSvZxloZbkJDG383q0awVAq600pc1nfqBcl0ice/WN9p4qLc39WhBShRTA== +"@esbuild/openbsd-x64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.6.tgz#b1b5aaa2c9028e90a2bef6774a9c67451f53f164" + integrity sha512-fFqTVEktM1PGs2sLKH4M5mhAVEzGpeZJuasAMRnvDZNCV0Cjvm1Hu35moL2vC0DOrAQjNTvj4zWrol/lwQ8Deg== + "@esbuild/sunos-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d" @@ -835,6 +946,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.5.tgz#9efc4eb9539a7be7d5a05ada52ee43cda0d8e2dd" integrity sha512-dGZkBXaafuKLpDSjKcB0ax0FL36YXCvJNnztjKV+6CO82tTYVDSH2lifitJ29jxRMoUhgkg9a+VA/B03WK5lcg== +"@esbuild/sunos-x64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.6.tgz#b51b648cea77c62b1934a4fdcfee7aaa9de174cb" + integrity sha512-M+XIAnBpaNvaVAhbe3uBXtgWyWynSdlww/JNZws0FlMPSBy+EpatPXNIlKAdtbFVII9OpX91ZfMb17TU3JKTBA== + "@esbuild/win32-arm64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9" @@ -845,6 +961,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.5.tgz#29f8184afa7a02a956ebda4ed638099f4b8ff198" integrity sha512-dWVjD9y03ilhdRQ6Xig1NWNgfLtf2o/STKTS+eZuF90fI2BhbwD6WlaiCGKptlqXlURVB5AUOxUj09LuwKGDTg== +"@esbuild/win32-arm64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.6.tgz#34e5665f239047c302c8d153406c87db22afd58a" + integrity sha512-2DchFXn7vp/B6Tc2eKdTsLzE0ygqKkNUhUBCNtMx2Llk4POIVMUq5rUYjdcedFlGLeRe1uLCpVvCmE+G8XYybA== + "@esbuild/win32-ia32@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102" @@ -855,6 +976,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.5.tgz#f3de07afb292ecad651ae4bb8727789de2d95b05" integrity sha512-4liggWIA4oDgUxqpZwrDhmEfAH4d0iljanDOK7AnVU89T6CzHon/ony8C5LeOdfgx60x5cnQJFZwEydVlYx4iw== +"@esbuild/win32-ia32@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.6.tgz#f7aaebe325e67f44c0a738e80a98221504677b4a" + integrity sha512-PBo/HPDQllyWdjwAVX+Gl2hH0dfBydL97BAH/grHKC8fubqp02aL4S63otZ25q3sBdINtOBbz1qTZQfXbP4VBg== + "@esbuild/win32-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d" @@ -865,6 +991,11 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.5.tgz#faad84c41ba12e3a0acb52571df9bff37bee75f6" integrity sha512-czTrygUsB/jlM8qEW5MD8bgYU2Xg14lo6kBDXW6HdxKjh8M5PzETGiSHaz9MtbXBYDloHNUAUW2tMiKW4KM9Mw== +"@esbuild/win32-x64@0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.6.tgz#7134e5dea1f5943b013e96fc34f9638a5f3d7e3e" + integrity sha512-OE7yIdbDif2kKfrGa+V0vx/B3FJv2L4KnIiLlvtibPyO9UkgO3rzYE0HhpREo2vmJ1Ixq1zwm9/0er+3VOSZJA== + "@eslint-community/eslint-utils@^4.2.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -1042,6 +1173,18 @@ jest-util "^29.5.0" slash "^3.0.0" +"@jest/console@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" + integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + "@jest/core@^28.1.3": version "28.1.3" resolved "https://registry.yarnpkg.com/@jest/core/-/core-28.1.3.tgz#0ebf2bd39840f1233cd5f2d1e6fc8b71bd5a1ac7" @@ -1111,6 +1254,40 @@ slash "^3.0.0" strip-ansi "^6.0.0" +"@jest/core@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" + integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== + dependencies: + "@jest/console" "^29.7.0" + "@jest/reporters" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^29.7.0" + jest-config "^29.7.0" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-resolve-dependencies "^29.7.0" + jest-runner "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + jest-watcher "^29.7.0" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + "@jest/environment@>=27", "@jest/environment@^29.5.0": version "29.5.0" resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.5.0.tgz#9152d56317c1fdb1af389c46640ba74ef0bb4c65" @@ -1131,6 +1308,16 @@ "@types/node" "*" jest-mock "^28.1.3" +"@jest/environment@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" + integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== + dependencies: + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + "@jest/expect-utils@^28.1.3": version "28.1.3" resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-28.1.3.tgz#58561ce5db7cd253a7edddbc051fb39dda50f525" @@ -1145,6 +1332,13 @@ dependencies: jest-get-type "^29.4.3" +"@jest/expect-utils@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" + integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== + dependencies: + jest-get-type "^29.6.3" + "@jest/expect@^28.1.3": version "28.1.3" resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-28.1.3.tgz#9ac57e1d4491baca550f6bdbd232487177ad6a72" @@ -1161,6 +1355,14 @@ expect "^29.5.0" jest-snapshot "^29.5.0" +"@jest/expect@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" + integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== + dependencies: + expect "^29.7.0" + jest-snapshot "^29.7.0" + "@jest/fake-timers@>=27", "@jest/fake-timers@^29.5.0": version "29.5.0" resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.5.0.tgz#d4d09ec3286b3d90c60bdcd66ed28d35f1b4dc2c" @@ -1185,6 +1387,18 @@ jest-mock "^28.1.3" jest-util "^28.1.3" +"@jest/fake-timers@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" + integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== + dependencies: + "@jest/types" "^29.6.3" + "@sinonjs/fake-timers" "^10.0.2" + "@types/node" "*" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-util "^29.7.0" + "@jest/globals@^28.1.3": version "28.1.3" resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-28.1.3.tgz#a601d78ddc5fdef542728309894895b4a42dc333" @@ -1204,6 +1418,16 @@ "@jest/types" "^29.5.0" jest-mock "^29.5.0" +"@jest/globals@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" + integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/types" "^29.6.3" + jest-mock "^29.7.0" + "@jest/reporters@^28.1.3": version "28.1.3" resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-28.1.3.tgz#9adf6d265edafc5fc4a434cfb31e2df5a67a369a" @@ -1265,6 +1489,36 @@ strip-ansi "^6.0.0" v8-to-istanbul "^9.0.1" +"@jest/reporters@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" + integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^6.0.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + jest-worker "^29.7.0" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" + "@jest/schemas@^28.1.3": version "28.1.3" resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-28.1.3.tgz#ad8b86a66f11f33619e3d7e1dcddd7f2d40ff905" @@ -1279,6 +1533,13 @@ dependencies: "@sinclair/typebox" "^0.25.16" +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + "@jest/source-map@^28.1.2": version "28.1.2" resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-28.1.2.tgz#7fe832b172b497d6663cdff6c13b0a920e139e24" @@ -1297,6 +1558,15 @@ callsites "^3.0.0" graceful-fs "^4.2.9" +"@jest/source-map@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" + integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== + dependencies: + "@jridgewell/trace-mapping" "^0.3.18" + callsites "^3.0.0" + graceful-fs "^4.2.9" + "@jest/test-result@^28.1.3": version "28.1.3" resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-28.1.3.tgz#5eae945fd9f4b8fcfce74d239e6f725b6bf076c5" @@ -1317,6 +1587,16 @@ "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" +"@jest/test-result@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" + integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== + dependencies: + "@jest/console" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + "@jest/test-sequencer@^28.1.3": version "28.1.3" resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-28.1.3.tgz#9d0c283d906ac599c74bde464bc0d7e6a82886c3" @@ -1337,6 +1617,16 @@ jest-haste-map "^29.5.0" slash "^3.0.0" +"@jest/test-sequencer@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" + integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== + dependencies: + "@jest/test-result" "^29.7.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + slash "^3.0.0" + "@jest/transform@^28.1.3": version "28.1.3" resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-28.1.3.tgz#59d8098e50ab07950e0f2fc0fc7ec462371281b0" @@ -1379,6 +1669,27 @@ slash "^3.0.0" write-file-atomic "^4.0.2" +"@jest/transform@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" + integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" + "@jest/types@>=27", "@jest/types@^29.5.0": version "29.5.0" resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.5.0.tgz#f59ef9b031ced83047c67032700d8c807d6e1593" @@ -1403,6 +1714,18 @@ "@types/yargs" "^17.0.8" chalk "^4.0.0" +"@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== + dependencies: + "@jest/schemas" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + "@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": version "0.3.3" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" @@ -1417,6 +1740,11 @@ resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + "@jridgewell/set-array@^1.0.1": version "1.1.2" resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" @@ -1427,7 +1755,7 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.15": +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15": version "1.4.15" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== @@ -1440,6 +1768,14 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" +"@jridgewell/trace-mapping@^0.3.18": + version "0.3.20" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f" + integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + "@jsdevtools/ono@^7.1.3": version "7.1.3" resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796" @@ -1514,6 +1850,16 @@ http-cache-semantics "^4.1.0" undici "5.20.0" +"@miniflare/cache@2.14.1": + version "2.14.1" + resolved "https://registry.yarnpkg.com/@miniflare/cache/-/cache-2.14.1.tgz#2c6a165caca63a39b1aa56c5152a583be8330398" + integrity sha512-f/o6UBV6UX+MlhjcEch73/wjQvvNo37dgYmP6Pn2ax1/mEHhJ7allNAqenmonT4djNeyB3eEYV3zUl54wCEwrg== + dependencies: + "@miniflare/core" "2.14.1" + "@miniflare/shared" "2.14.1" + http-cache-semantics "^4.1.0" + undici "5.20.0" + "@miniflare/core@2.14.0": version "2.14.0" resolved "https://registry.yarnpkg.com/@miniflare/core/-/core-2.14.0.tgz#daf1e844686722a0e2b9b0638358f663d0712cec" @@ -1530,6 +1876,22 @@ undici "5.20.0" urlpattern-polyfill "^4.0.3" +"@miniflare/core@2.14.1": + version "2.14.1" + resolved "https://registry.yarnpkg.com/@miniflare/core/-/core-2.14.1.tgz#545199da6598c8295e24f629a1aa1d44bad1f6ba" + integrity sha512-d+SGAda/VoXq+SKz04oq8ATUwQw5755L87fgPR8pTdR2YbWkxdbmEm1z2olOpDiUjcR86aN6NtCjY6tUC7fqaw== + dependencies: + "@iarna/toml" "^2.2.5" + "@miniflare/queues" "2.14.1" + "@miniflare/shared" "2.14.1" + "@miniflare/watcher" "2.14.1" + busboy "^1.6.0" + dotenv "^10.0.0" + kleur "^4.1.4" + set-cookie-parser "^2.4.8" + undici "5.20.0" + urlpattern-polyfill "^4.0.3" + "@miniflare/d1@2.14.0": version "2.14.0" resolved "https://registry.yarnpkg.com/@miniflare/d1/-/d1-2.14.0.tgz#d384e486bee21d795956e53b255b173e48a7d1b7" @@ -1538,6 +1900,14 @@ "@miniflare/core" "2.14.0" "@miniflare/shared" "2.14.0" +"@miniflare/d1@2.14.1": + version "2.14.1" + resolved "https://registry.yarnpkg.com/@miniflare/d1/-/d1-2.14.1.tgz#016ec975981c831ef5e036d2243dc678cec6ab4e" + integrity sha512-MulDDBsDD8o5DwiqdMeJZy2vLoMji+NWnLcuibSag2mayA0LJcp0eHezseZNkW+knciWR1gMP8Xpa4Q1KwkbKA== + dependencies: + "@miniflare/core" "2.14.1" + "@miniflare/shared" "2.14.1" + "@miniflare/durable-objects@2.14.0": version "2.14.0" resolved "https://registry.yarnpkg.com/@miniflare/durable-objects/-/durable-objects-2.14.0.tgz#1c913e774e949dfe82077cb82fe2ec6dd7bfb96a" @@ -1548,6 +1918,16 @@ "@miniflare/storage-memory" "2.14.0" undici "5.20.0" +"@miniflare/durable-objects@2.14.1": + version "2.14.1" + resolved "https://registry.yarnpkg.com/@miniflare/durable-objects/-/durable-objects-2.14.1.tgz#48f29847afd7699e369fb0caa1a4fa23c1d39315" + integrity sha512-T+oHGw5GcEIilkzrf0xDES7jzLVqcXJzSGsEIWqnBFLtdlKmrZF679ulRLBbyMVgvpQz6FRONh9jTH1XIiuObQ== + dependencies: + "@miniflare/core" "2.14.1" + "@miniflare/shared" "2.14.1" + "@miniflare/storage-memory" "2.14.1" + undici "5.20.0" + "@miniflare/html-rewriter@2.14.0": version "2.14.0" resolved "https://registry.yarnpkg.com/@miniflare/html-rewriter/-/html-rewriter-2.14.0.tgz#b3edb2c3889fb9da7d25517de33eaa50473beeef" @@ -1558,6 +1938,16 @@ html-rewriter-wasm "^0.4.1" undici "5.20.0" +"@miniflare/html-rewriter@2.14.1": + version "2.14.1" + resolved "https://registry.yarnpkg.com/@miniflare/html-rewriter/-/html-rewriter-2.14.1.tgz#e4f109d5e0efe862717b1ff33e75644d538618b1" + integrity sha512-vp4uZXuEKhtIaxoXa7jgDAPItlzjbfoUqYWp+fwDKv4J4mfQnzzs/5hwjbE7+Ihm/KNI0zNi8P0sSWjIRFl6ng== + dependencies: + "@miniflare/core" "2.14.1" + "@miniflare/shared" "2.14.1" + html-rewriter-wasm "^0.4.1" + undici "5.20.0" + "@miniflare/kv@2.14.0": version "2.14.0" resolved "https://registry.yarnpkg.com/@miniflare/kv/-/kv-2.14.0.tgz#c0f3043d981e58bed33629e42373b5335e79e5e5" @@ -1565,6 +1955,13 @@ dependencies: "@miniflare/shared" "2.14.0" +"@miniflare/kv@2.14.1": + version "2.14.1" + resolved "https://registry.yarnpkg.com/@miniflare/kv/-/kv-2.14.1.tgz#6d04b7f11969baa1efc5c84d6c0ca0003afafa0a" + integrity sha512-Gp07Wcszle7ptsoO8mCtKQRs0AbQnYo1rgnxUcsTL3xJJaHXEA/B9EKSADS2XzJMeY4PgUOHU6Rf08OOF2yWag== + dependencies: + "@miniflare/shared" "2.14.1" + "@miniflare/queues@2.14.0": version "2.14.0" resolved "https://registry.yarnpkg.com/@miniflare/queues/-/queues-2.14.0.tgz#925557d58520cbef21b66e94768e33dd0c376ef9" @@ -1572,6 +1969,13 @@ dependencies: "@miniflare/shared" "2.14.0" +"@miniflare/queues@2.14.1": + version "2.14.1" + resolved "https://registry.yarnpkg.com/@miniflare/queues/-/queues-2.14.1.tgz#ce586e08b5b4dbdae6c5ed0d76317336269554c0" + integrity sha512-uBzrbBkIgtNoztDpmMMISg/brYtxLHRE7oTaN8OVnq3bG+3nF9kQC42HUz+Vg+sf65UlvhSaqkjllgx+fNtOxQ== + dependencies: + "@miniflare/shared" "2.14.1" + "@miniflare/r2@2.14.0": version "2.14.0" resolved "https://registry.yarnpkg.com/@miniflare/r2/-/r2-2.14.0.tgz#fd032cfaff3141a72e140fec741a8ac0cf8d0133" @@ -1581,6 +1985,15 @@ "@miniflare/shared" "2.14.0" undici "5.20.0" +"@miniflare/r2@2.14.1": + version "2.14.1" + resolved "https://registry.yarnpkg.com/@miniflare/r2/-/r2-2.14.1.tgz#57a352576746a6f7a19726e7559a6e5607c4afb9" + integrity sha512-grOMnGf2XSicbgxMYMBfWE37k/e7l5NnwXZIViQ+N06uksp+MLA8E6yKQNtvrWQS66TM8gBvMnWo96OFmYjb6Q== + dependencies: + "@miniflare/core" "2.14.1" + "@miniflare/shared" "2.14.1" + undici "5.20.0" + "@miniflare/runner-vm@2.14.0": version "2.14.0" resolved "https://registry.yarnpkg.com/@miniflare/runner-vm/-/runner-vm-2.14.0.tgz#cd4a61e7d81c4e2239f8c528c35abd7ed557ae5b" @@ -1588,6 +2001,13 @@ dependencies: "@miniflare/shared" "2.14.0" +"@miniflare/runner-vm@2.14.1": + version "2.14.1" + resolved "https://registry.yarnpkg.com/@miniflare/runner-vm/-/runner-vm-2.14.1.tgz#401beb39f34151c7a12ce5018decb78767bfe5c2" + integrity sha512-UobsGM0ICVPDlJD54VPDSx0EXrIY3nJMXBy2zIFuuUOz4hQKXvMQ6jtAlJ8UNKer+XXI3Mb/9R/gfU8r6kxIMA== + dependencies: + "@miniflare/shared" "2.14.1" + "@miniflare/shared-test-environment@2.14.0": version "2.14.0" resolved "https://registry.yarnpkg.com/@miniflare/shared-test-environment/-/shared-test-environment-2.14.0.tgz#8762c42a47743f78ed07432ca7d2e729ce84d4c5" @@ -1607,6 +2027,25 @@ "@miniflare/storage-memory" "2.14.0" "@miniflare/web-sockets" "2.14.0" +"@miniflare/shared-test-environment@2.14.1": + version "2.14.1" + resolved "https://registry.yarnpkg.com/@miniflare/shared-test-environment/-/shared-test-environment-2.14.1.tgz#128ac33feba0ebe932f38a550e1b3f1207d396f1" + integrity sha512-hfactEWiHuHOmE29XFG8oLNCF6+HqjD6Mb80CzidcVmLlBTEtSC3PEF+DXPyvNdLXpBolZMKOuC/yzzloWvACA== + dependencies: + "@cloudflare/workers-types" "^4.20221111.1" + "@miniflare/cache" "2.14.1" + "@miniflare/core" "2.14.1" + "@miniflare/d1" "2.14.1" + "@miniflare/durable-objects" "2.14.1" + "@miniflare/html-rewriter" "2.14.1" + "@miniflare/kv" "2.14.1" + "@miniflare/queues" "2.14.1" + "@miniflare/r2" "2.14.1" + "@miniflare/shared" "2.14.1" + "@miniflare/sites" "2.14.1" + "@miniflare/storage-memory" "2.14.1" + "@miniflare/web-sockets" "2.14.1" + "@miniflare/shared@2.14.0": version "2.14.0" resolved "https://registry.yarnpkg.com/@miniflare/shared/-/shared-2.14.0.tgz#bc625dc15bbb2f5b17a6a8ec65258faf61013bda" @@ -1617,6 +2056,16 @@ npx-import "^1.1.4" picomatch "^2.3.1" +"@miniflare/shared@2.14.1": + version "2.14.1" + resolved "https://registry.yarnpkg.com/@miniflare/shared/-/shared-2.14.1.tgz#b150787e2b846f43085b15747b5e6f8a90fa1634" + integrity sha512-73GnLtWn5iP936ctE6ZJrMqGu134KOoIIveq5Yd/B+NnbFfzpuzjCpkLrnqjkDdsxDbruXSb5eTR/SmAdpJxZQ== + dependencies: + "@types/better-sqlite3" "^7.6.0" + kleur "^4.1.4" + npx-import "^1.1.4" + picomatch "^2.3.1" + "@miniflare/sites@2.14.0": version "2.14.0" resolved "https://registry.yarnpkg.com/@miniflare/sites/-/sites-2.14.0.tgz#e2653b5e28828ae198948a00111f2980b8416438" @@ -1626,6 +2075,15 @@ "@miniflare/shared" "2.14.0" "@miniflare/storage-file" "2.14.0" +"@miniflare/sites@2.14.1": + version "2.14.1" + resolved "https://registry.yarnpkg.com/@miniflare/sites/-/sites-2.14.1.tgz#f2bc8308c5488aea961d7a82ffe4f91d23411fb0" + integrity sha512-AbbIcU6VBeaNqVgMiLMWN2a09eX3jZmjaEi0uKqufVDqW/QIz47/30aC0O9qTe+XYpi3jjph/Ux7uEY8Z+enMw== + dependencies: + "@miniflare/kv" "2.14.1" + "@miniflare/shared" "2.14.1" + "@miniflare/storage-file" "2.14.1" + "@miniflare/storage-file@2.14.0": version "2.14.0" resolved "https://registry.yarnpkg.com/@miniflare/storage-file/-/storage-file-2.14.0.tgz#5f8d7c5e9b744793e94b887dc78280c796ea0e75" @@ -1634,6 +2092,14 @@ "@miniflare/shared" "2.14.0" "@miniflare/storage-memory" "2.14.0" +"@miniflare/storage-file@2.14.1": + version "2.14.1" + resolved "https://registry.yarnpkg.com/@miniflare/storage-file/-/storage-file-2.14.1.tgz#4cf14baad1fee75d523a6cf7ea7bfabd6a7d7dd1" + integrity sha512-faZu9tRSW6c/looVFI/ZhkdGsIc9NfNCbSl3jJRmm7xgyZ+/S+dQ5JtGVbVsUIX8YGWDyE2j3oWCGCjxGLEpkg== + dependencies: + "@miniflare/shared" "2.14.1" + "@miniflare/storage-memory" "2.14.1" + "@miniflare/storage-memory@2.14.0": version "2.14.0" resolved "https://registry.yarnpkg.com/@miniflare/storage-memory/-/storage-memory-2.14.0.tgz#5fb0bf10194bbc370cb4640a14ca00a148f1e5a3" @@ -1641,6 +2107,13 @@ dependencies: "@miniflare/shared" "2.14.0" +"@miniflare/storage-memory@2.14.1": + version "2.14.1" + resolved "https://registry.yarnpkg.com/@miniflare/storage-memory/-/storage-memory-2.14.1.tgz#9615de975a85a25b3dccaa9f085c955550e364f2" + integrity sha512-lfQbQwopVWd4W5XzrYdp0rhk3dJpvSmv1Wwn9RhNO20WrcuoxpdSzbmpBahsgYVg+OheVaEbS6RpFqdmwwLTog== + dependencies: + "@miniflare/shared" "2.14.1" + "@miniflare/watcher@2.14.0": version "2.14.0" resolved "https://registry.yarnpkg.com/@miniflare/watcher/-/watcher-2.14.0.tgz#de8f2f1d51698f7e1fa57941607798f541f4a092" @@ -1648,6 +2121,13 @@ dependencies: "@miniflare/shared" "2.14.0" +"@miniflare/watcher@2.14.1": + version "2.14.1" + resolved "https://registry.yarnpkg.com/@miniflare/watcher/-/watcher-2.14.1.tgz#2fe44470df44a1eff1313597ea2389c06a8f9b05" + integrity sha512-dkFvetm5wk6pwunlYb/UkI0yFNb3otLpRm5RDywMUzqObEf+rCiNNAbJe3HUspr2ncZVAaRWcEaDh82vYK5cmw== + dependencies: + "@miniflare/shared" "2.14.1" + "@miniflare/web-sockets@2.14.0": version "2.14.0" resolved "https://registry.yarnpkg.com/@miniflare/web-sockets/-/web-sockets-2.14.0.tgz#1dd7b3694a280a526f8c6a960a8a3d26e979eded" @@ -1658,6 +2138,33 @@ undici "5.20.0" ws "^8.2.2" +"@miniflare/web-sockets@2.14.1": + version "2.14.1" + resolved "https://registry.yarnpkg.com/@miniflare/web-sockets/-/web-sockets-2.14.1.tgz#d48ba704c32c19db7d0cfc88107e1d1e364e9b62" + integrity sha512-3N//L5EjF7+xXd7qCLR2ylUwm8t2MKyGPGWEtRBrQ2xqYYWhewKTjlquHCOPU5Irnnd/4BhTmFA55MNrq7m4Nw== + dependencies: + "@miniflare/core" "2.14.1" + "@miniflare/shared" "2.14.1" + undici "5.20.0" + ws "^8.2.2" + +"@mswjs/cookies@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@mswjs/cookies/-/cookies-1.1.0.tgz#1528eb43630caf83a1d75d5332b30e75e9bb1b5b" + integrity sha512-0ZcCVQxifZmhwNBoQIrystCb+2sWBY2Zw8lpfJBPCHGCA/HWqehITeCRVIv4VMy8MPlaHo2w2pTHFV2pFfqKPw== + +"@mswjs/interceptors@^0.25.11": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@mswjs/interceptors/-/interceptors-0.25.12.tgz#f54d9e432aa5d3b149aa6c6356e611ac12eba5d4" + integrity sha512-a+zyoR01cPQeukSmaDEkE6aMwSjjfcT5ILzsyxmctEeCePnc2DMOd0X8Fn9bytq1IsAfMxJf/lu2aTfdivDbRg== + dependencies: + "@open-draft/deferred-promise" "^2.2.0" + "@open-draft/logger" "^0.3.0" + "@open-draft/until" "^2.0.0" + is-node-process "^1.2.0" + outvariant "^1.2.1" + strict-event-emitter "^0.5.1" + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -1787,6 +2294,24 @@ dependencies: "@octokit/openapi-types" "^12.11.0" +"@open-draft/deferred-promise@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz#4a822d10f6f0e316be4d67b4d4f8c9a124b073bd" + integrity sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA== + +"@open-draft/logger@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@open-draft/logger/-/logger-0.3.0.tgz#2b3ab1242b360aa0adb28b85f5d7da1c133a0954" + integrity sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ== + dependencies: + is-node-process "^1.2.0" + outvariant "^1.4.0" + +"@open-draft/until@^2.0.0", "@open-draft/until@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@open-draft/until/-/until-2.1.0.tgz#0acf32f470af2ceaf47f095cdecd40d68666efda" + integrity sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg== + "@opentelemetry/api@^1.0.0": version "1.4.1" resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.4.1.tgz#ff22eb2e5d476fbc2450a196e40dd243cc20c28f" @@ -1924,6 +2449,66 @@ estree-walker "^2.0.2" picomatch "^2.3.1" +"@rollup/rollup-android-arm-eabi@4.5.0": + version "4.5.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.5.0.tgz#5984f98288150a2c34928de023bbd122d61ce754" + integrity sha512-OINaBGY+Wc++U0rdr7BLuFClxcoWaVW3vQYqmQq6B3bqQ/2olkaoz+K8+af/Mmka/C2yN5j+L9scBkv4BtKsDA== + +"@rollup/rollup-android-arm64@4.5.0": + version "4.5.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.5.0.tgz#8456a8c623cca4042ae4bf2ce03d875a02433191" + integrity sha512-UdMf1pOQc4ZmUA/NTmKhgJTBimbSKnhPS2zJqucqFyBRFPnPDtwA8MzrGNTjDeQbIAWfpJVAlxejw+/lQyBK/w== + +"@rollup/rollup-darwin-arm64@4.5.0": + version "4.5.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.5.0.tgz#76be6832eee21dabc28f84f9f54fbfcc66615992" + integrity sha512-L0/CA5p/idVKI+c9PcAPGorH6CwXn6+J0Ys7Gg1axCbTPgI8MeMlhA6fLM9fK+ssFhqogMHFC8HDvZuetOii7w== + +"@rollup/rollup-darwin-x64@4.5.0": + version "4.5.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.5.0.tgz#66bd162a3fea48cb1cef50cedccfbeee5685b444" + integrity sha512-QZCbVqU26mNlLn8zi/XDDquNmvcr4ON5FYAHQQsyhrHx8q+sQi/6xduoznYXwk/KmKIXG5dLfR0CvY+NAWpFYQ== + +"@rollup/rollup-linux-arm-gnueabihf@4.5.0": + version "4.5.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.5.0.tgz#a0e6b2a1d67a4ba0c2a61985175f65c05abc5f73" + integrity sha512-VpSQ+xm93AeV33QbYslgf44wc5eJGYfYitlQzAi3OObu9iwrGXEnmu5S3ilkqE3Pr/FkgOiJKV/2p0ewf4Hrtg== + +"@rollup/rollup-linux-arm64-gnu@4.5.0": + version "4.5.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.5.0.tgz#5434b844a47ba4e35602ee312de9f39b38b1777b" + integrity sha512-OrEyIfpxSsMal44JpEVx9AEcGpdBQG1ZuWISAanaQTSMeStBW+oHWwOkoqR54bw3x8heP8gBOyoJiGg+fLY8qQ== + +"@rollup/rollup-linux-arm64-musl@4.5.0": + version "4.5.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.5.0.tgz#149cab95107821fe4ae46d5f2c0658c5b0e56b9c" + integrity sha512-1H7wBbQuE6igQdxMSTjtFfD+DGAudcYWhp106z/9zBA8OQhsJRnemO4XGavdzHpGhRtRxbgmUGdO3YQgrWf2RA== + +"@rollup/rollup-linux-x64-gnu@4.5.0": + version "4.5.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.5.0.tgz#6929bf3013e9d599605953ea1bc51f35376bfff7" + integrity sha512-FVyFI13tXw5aE65sZdBpNjPVIi4Q5mARnL/39UIkxvSgRAIqCo5sCpCELk0JtXHGee2owZz5aNLbWNfBHzr71Q== + +"@rollup/rollup-linux-x64-musl@4.5.0": + version "4.5.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.5.0.tgz#a17f5decabf05b74aad684de56cf43a72a289a0b" + integrity sha512-eBPYl2sLpH/o8qbSz6vPwWlDyThnQjJfcDOGFbNjmjb44XKC1F5dQfakOsADRVrXCNzM6ZsSIPDG5dc6HHLNFg== + +"@rollup/rollup-win32-arm64-msvc@4.5.0": + version "4.5.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.5.0.tgz#f145f10c33aa187a11fd60933465be46667e6e42" + integrity sha512-xaOHIfLOZypoQ5U2I6rEaugS4IYtTgP030xzvrBf5js7p9WI9wik07iHmsKaej8Z83ZDxN5GyypfoyKV5O5TJA== + +"@rollup/rollup-win32-ia32-msvc@4.5.0": + version "4.5.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.5.0.tgz#798614b191f9ce1dc58079d1dfbc234c71df9e0e" + integrity sha512-Al6quztQUrHwcOoU2TuFblUQ5L+/AmPBXFR6dUvyo4nRj2yQRK0WIUaGMF/uwKulvRcXkpHe3k9A8Vf93VDktA== + +"@rollup/rollup-win32-x64-msvc@4.5.0": + version "4.5.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.5.0.tgz#748970e066839e33ed8c935061e370c4ab050517" + integrity sha512-8kdW+brNhI/NzJ4fxDufuJUjepzINqJKLGHuxyAtpPG9bMbn8P5mtaCcbOm0EzLJ+atg+kF9dwg8jpclkVqx5w== + "@samverschueren/stream-to-observable@^0.3.0", "@samverschueren/stream-to-observable@^0.3.1": version "0.3.1" resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.1.tgz#a21117b19ee9be70c379ec1877537ef2e1c63301" @@ -1973,6 +2558,11 @@ resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718" integrity sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ== +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + "@sinclair/typebox@^0.31.15": version "0.31.22" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.31.22.tgz#f13fa4050a7e883d252365902e38186fa0dc8ab8" @@ -2129,6 +2719,11 @@ resolved "https://registry.yarnpkg.com/@types/comment-json/-/comment-json-1.1.1.tgz#b4ae889912a93e64619f97989aecaff8ce889dca" integrity sha512-U70oEqvnkeSSp8BIJwJclERtT13rd9ejK7XkIzMCQQePZe3VW1b7iQggXyW4ZvfGtGeXD0pZw24q5iWNe++HqQ== +"@types/cookie@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d" + integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q== + "@types/debug@^4.0.0": version "4.1.8" resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.8.tgz#cef723a5d0a90990313faec2d1e22aee5eecb317" @@ -2224,6 +2819,19 @@ expect "^29.0.0" pretty-format "^29.0.0" +"@types/jest@^29.5.7": + version "29.5.8" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.8.tgz#ed5c256fe2bc7c38b1915ee5ef1ff24a3427e120" + integrity sha512-fXEFTxMV2Co8ZF5aYFJv+YeA08RTYJfhtN5c9JSv/mFEMe+xxjufCb+PHL+bJcMs/ebPUsBu+UNTEz+ydXrR6g== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + +"@types/js-levenshtein@^1.1.1": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@types/js-levenshtein/-/js-levenshtein-1.1.3.tgz#a6fd0bdc8255b274e5438e0bfb25f154492d1106" + integrity sha512-jd+Q+sD20Qfu9e2aEXogiO3vpOC1PYJOUdyN9gvs4Qrvkg4wF43L5OhqrPeokdv8TL0/mXoYfpkcoGZMNN2pkQ== + "@types/json-schema@^7.0.6", "@types/json-schema@^7.0.9": version "7.0.12" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" @@ -2351,6 +2959,11 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== +"@types/statuses@^2.0.1": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/statuses/-/statuses-2.0.4.tgz#041143ba4a918e8f080f8b0ffbe3d4cb514e2315" + integrity sha512-eqNDvZsCNY49OAXB0Firg/Sc2BgoWsntsLUdybGFOhAfCD6QJ2n9HXUIHGqt5qjrxmMv4wS8WLAw43ZkKcJ8Pw== + "@types/swagger-ui-dist@^3.30.3": version "3.30.3" resolved "https://registry.yarnpkg.com/@types/swagger-ui-dist/-/swagger-ui-dist-3.30.3.tgz#ae72f08754f5674cc8fe5683785363fab5697d2b" @@ -2510,6 +3123,11 @@ loupe "^2.3.6" pretty-format "^29.5.0" +"@yarnpkg/lockfile@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" + integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== + abbrev@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -2909,6 +3527,11 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== + available-typed-arrays@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" @@ -2955,6 +3578,19 @@ babel-jest@^29.5.0: graceful-fs "^4.2.9" slash "^3.0.0" +babel-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" + integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== + dependencies: + "@jest/transform" "^29.7.0" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.6.3" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + babel-plugin-istanbul@^6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" @@ -2986,6 +3622,16 @@ babel-plugin-jest-hoist@^29.5.0: "@types/babel__core" "^7.1.14" "@types/babel__traverse" "^7.0.6" +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + babel-preset-current-node-syntax@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" @@ -3020,6 +3666,14 @@ babel-preset-jest@^29.5.0: babel-plugin-jest-hoist "^29.5.0" babel-preset-current-node-syntax "^1.0.0" +babel-preset-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== + dependencies: + babel-plugin-jest-hoist "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + bail@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/bail/-/bail-2.0.2.tgz#d26f5cd8fe5d6f832a31517b9f7c356040ba6d5d" @@ -3341,6 +3995,15 @@ call-bind@^1.0.0, call-bind@^1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.2" +call-bind@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" + integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== + dependencies: + function-bind "^1.1.2" + get-intrinsic "^1.2.1" + set-function-length "^1.1.1" + call-me-maybe@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.2.tgz#03f964f19522ba643b1b0693acb9152fe2074baa" @@ -3491,7 +4154,7 @@ check-error@^1.0.3: dependencies: get-func-name "^2.0.2" -chokidar@^3.0.2, chokidar@^3.5.1: +chokidar@^3.0.2, chokidar@^3.4.2, chokidar@^3.5.1: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== @@ -3526,6 +4189,11 @@ ci-info@^3.1.0, ci-info@^3.2.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== +ci-info@^3.7.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + cjs-module-lexer@^1.0.0: version "1.2.3" resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107" @@ -3909,6 +4577,19 @@ crc32-stream@^4.0.2: crc-32 "^1.2.0" readable-stream "^3.4.0" +create-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" + integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-config "^29.7.0" + jest-util "^29.7.0" + prompts "^2.0.1" + cross-env@^5.1.3: version "5.2.1" resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-5.2.1.tgz#b2c76c1ca7add66dc874d11798466094f551b34d" @@ -4130,6 +4811,11 @@ dedent@^0.7.0: resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== +dedent@^1.0.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.1.tgz#4f3fc94c8b711e9bb2800d185cd6ad20f2a90aff" + integrity sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg== + deep-eql@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" @@ -4197,6 +4883,15 @@ defer-to-connect@^2.0.0: resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== +define-data-property@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" + integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ== + dependencies: + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + define-lazy-prop@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz#dbb19adfb746d7fc6d734a06b72f4a00d021255f" @@ -4310,6 +5005,11 @@ diff-sequences@^29.4.3: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2" integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA== +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== + diff@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40" @@ -4637,6 +5337,34 @@ esbuild@^0.18.10, esbuild@^0.18.2: "@esbuild/win32-ia32" "0.18.20" "@esbuild/win32-x64" "0.18.20" +esbuild@^0.19.2: + version "0.19.6" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.6.tgz#baa0e8b6b9e655c54ffd57f1772e44677a7931cc" + integrity sha512-Xl7dntjA2OEIvpr9j0DVxxnog2fyTGnyVoQXAMQI6eR3mf9zCQds7VIKUDCotDgE/p4ncTgeRqgX8t5d6oP4Gw== + optionalDependencies: + "@esbuild/android-arm" "0.19.6" + "@esbuild/android-arm64" "0.19.6" + "@esbuild/android-x64" "0.19.6" + "@esbuild/darwin-arm64" "0.19.6" + "@esbuild/darwin-x64" "0.19.6" + "@esbuild/freebsd-arm64" "0.19.6" + "@esbuild/freebsd-x64" "0.19.6" + "@esbuild/linux-arm" "0.19.6" + "@esbuild/linux-arm64" "0.19.6" + "@esbuild/linux-ia32" "0.19.6" + "@esbuild/linux-loong64" "0.19.6" + "@esbuild/linux-mips64el" "0.19.6" + "@esbuild/linux-ppc64" "0.19.6" + "@esbuild/linux-riscv64" "0.19.6" + "@esbuild/linux-s390x" "0.19.6" + "@esbuild/linux-x64" "0.19.6" + "@esbuild/netbsd-x64" "0.19.6" + "@esbuild/openbsd-x64" "0.19.6" + "@esbuild/sunos-x64" "0.19.6" + "@esbuild/win32-arm64" "0.19.6" + "@esbuild/win32-ia32" "0.19.6" + "@esbuild/win32-x64" "0.19.6" + esbuild@^0.19.5: version "0.19.5" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.5.tgz#53a0e19dfbf61ba6c827d51a80813cf071239a8c" @@ -5127,6 +5855,17 @@ expect@^29.0.0, expect@^29.5.0: jest-message-util "^29.5.0" jest-util "^29.5.0" +expect@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" + integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== + dependencies: + "@jest/expect-utils" "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + exponential-backoff@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.1.tgz#64ac7526fe341ab18a39016cd22c787d01e00bf6" @@ -5356,6 +6095,13 @@ find-yarn-workspace-root2@1.2.16: micromatch "^4.0.2" pkg-dir "^4.2.0" +find-yarn-workspace-root@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz#f47fb8d239c900eb78179aa81b66673eac88f7bd" + integrity sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ== + dependencies: + micromatch "^4.0.2" + firebase-auth-cloudflare-workers@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/firebase-auth-cloudflare-workers/-/firebase-auth-cloudflare-workers-1.1.0.tgz#46737bbcebbfef32a5c9b74bab13bbf24ae78445" @@ -5525,6 +6271,16 @@ fs-extra@^8.1.0: jsonfile "^4.0.0" universalify "^0.1.0" +fs-extra@^9.0.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + fs-minipass@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" @@ -5562,6 +6318,11 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + function.prototype.name@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" @@ -5661,6 +6422,16 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@ has-proto "^1.0.1" has-symbols "^1.0.3" +get-intrinsic@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" + integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA== + dependencies: + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" @@ -5992,7 +6763,7 @@ graceful-fs@4.2.10: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== -graceful-fs@^4.1.2, graceful-fs@^4.1.5, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.5, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -6012,6 +6783,11 @@ graphql@^16.5.0: resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.7.1.tgz#11475b74a7bff2aefd4691df52a0eca0abd9b642" integrity sha512-DRYR9tf+UGU0KOsMcKAlXeFfX89UiiIZ0dRU3mR0yJfu6OjZqUcp68NnFLnqQU5RexygFoDy1EW+ccOYcPfmHg== +graphql@^16.8.1: + version "16.8.1" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.8.1.tgz#1930a965bef1170603702acdb68aedd3f3cf6f07" + integrity sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw== + gtoken@^5.0.4: version "5.3.2" resolved "https://registry.yarnpkg.com/gtoken/-/gtoken-5.3.2.tgz#deb7dc876abe002178e0515e383382ea9446d58f" @@ -6116,6 +6892,13 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +hasown@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" + integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== + dependencies: + function-bind "^1.1.2" + hast-util-to-estree@^2.0.0: version "2.3.3" resolved "https://registry.yarnpkg.com/hast-util-to-estree/-/hast-util-to-estree-2.3.3.tgz#da60142ffe19a6296923ec222aba73339c8bf470" @@ -6142,6 +6925,11 @@ hast-util-whitespace@^2.0.0: resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz#0ec64e257e6fc216c7d14c8a1b74d27d650b4557" integrity sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng== +headers-polyfill@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/headers-polyfill/-/headers-polyfill-4.0.2.tgz#9115a76eee3ce8fbf95b6e3c6bf82d936785b44a" + integrity sha512-EWGTfnTqAO2L/j5HZgoM/3z82L7necsJ0pO9Tp0X1wil3PDLrkypTBRgVO2ExehEEvUycejZD3FuRaXpZZc3kw== + heap-js@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/heap-js/-/heap-js-2.3.0.tgz#8eed2cede31ec312aa696eef1d4df0565841f183" @@ -6664,6 +7452,11 @@ is-negative-zero@^2.0.2: resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== +is-node-process@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/is-node-process/-/is-node-process-1.2.0.tgz#ea02a1b90ddb3934a19aea414e88edef7e11d134" + integrity sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw== + is-npm@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-5.0.0.tgz#43e8d65cc56e1b67f8d47262cf667099193f45a8" @@ -6867,6 +7660,11 @@ isarray@0.0.1: resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -6911,6 +7709,17 @@ istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: istanbul-lib-coverage "^3.2.0" semver "^6.3.0" +istanbul-lib-instrument@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz#71e87707e8041428732518c6fb5211761753fbdf" + integrity sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^7.5.4" + istanbul-lib-report@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" @@ -6962,6 +7771,15 @@ jest-changed-files@^29.5.0: execa "^5.0.0" p-limit "^3.1.0" +jest-changed-files@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" + integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== + dependencies: + execa "^5.0.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + jest-circus@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-28.1.3.tgz#d14bd11cf8ee1a03d69902dc47b6bd4634ee00e4" @@ -7013,6 +7831,32 @@ jest-circus@^29.5.0: slash "^3.0.0" stack-utils "^2.0.3" +jest-circus@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" + integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^1.0.0" + is-generator-fn "^2.0.0" + jest-each "^29.7.0" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + pretty-format "^29.7.0" + pure-rand "^6.0.0" + slash "^3.0.0" + stack-utils "^2.0.3" + jest-cli@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-28.1.3.tgz#558b33c577d06de55087b8448d373b9f654e46b2" @@ -7049,6 +7893,23 @@ jest-cli@^29.5.0: prompts "^2.0.1" yargs "^17.3.1" +jest-cli@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" + integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== + dependencies: + "@jest/core" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + chalk "^4.0.0" + create-jest "^29.7.0" + exit "^0.1.2" + import-local "^3.0.2" + jest-config "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + yargs "^17.3.1" + jest-config@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-28.1.3.tgz#e315e1f73df3cac31447eed8b8740a477392ec60" @@ -7105,6 +7966,34 @@ jest-config@^29.5.0: slash "^3.0.0" strip-json-comments "^3.1.1" +jest-config@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" + integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.7.0" + "@jest/types" "^29.6.3" + babel-jest "^29.7.0" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.7.0" + jest-environment-node "^29.7.0" + jest-get-type "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-runner "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-json-comments "^3.1.1" + jest-diff@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-28.1.3.tgz#948a192d86f4e7a64c5264ad4da4877133d8792f" @@ -7125,6 +8014,16 @@ jest-diff@^29.5.0: jest-get-type "^29.4.3" pretty-format "^29.5.0" +jest-diff@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" + integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + jest-docblock@^28.1.1: version "28.1.1" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-28.1.1.tgz#6f515c3bf841516d82ecd57a62eed9204c2f42a8" @@ -7139,6 +8038,13 @@ jest-docblock@^29.4.3: dependencies: detect-newline "^3.0.0" +jest-docblock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" + integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== + dependencies: + detect-newline "^3.0.0" + jest-each@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-28.1.3.tgz#bdd1516edbe2b1f3569cfdad9acd543040028f81" @@ -7161,6 +8067,17 @@ jest-each@^29.5.0: jest-util "^29.5.0" pretty-format "^29.5.0" +jest-each@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" + integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + jest-get-type "^29.6.3" + jest-util "^29.7.0" + pretty-format "^29.7.0" + jest-environment-miniflare@^2.10.0, jest-environment-miniflare@^2.6.0: version "2.14.0" resolved "https://registry.yarnpkg.com/jest-environment-miniflare/-/jest-environment-miniflare-2.14.0.tgz#acf87d2cf63529eae178799a8a391629097b7145" @@ -7176,6 +8093,21 @@ jest-environment-miniflare@^2.10.0, jest-environment-miniflare@^2.6.0: jest-mock ">=27" jest-util ">=27" +jest-environment-miniflare@^2.14.1: + version "2.14.1" + resolved "https://registry.yarnpkg.com/jest-environment-miniflare/-/jest-environment-miniflare-2.14.1.tgz#45b63dfa00db73695c9760dd33b63545314384bc" + integrity sha512-IkyCJ7LJCIXE1xJaExPRVHTK+6RxFJYEQjaVnpMCn9gEXSnjZhFwxdD3uFJq3J9QtcuZKRFBKJurnmGFCV4otQ== + dependencies: + "@jest/environment" ">=27" + "@jest/fake-timers" ">=27" + "@jest/types" ">=27" + "@miniflare/queues" "2.14.1" + "@miniflare/runner-vm" "2.14.1" + "@miniflare/shared" "2.14.1" + "@miniflare/shared-test-environment" "2.14.1" + jest-mock ">=27" + jest-util ">=27" + jest-environment-node@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-28.1.3.tgz#7e74fe40eb645b9d56c0c4b70ca4357faa349be5" @@ -7200,6 +8132,18 @@ jest-environment-node@^29.5.0: jest-mock "^29.5.0" jest-util "^29.5.0" +jest-environment-node@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" + integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + jest-util "^29.7.0" + jest-get-type@^28.0.2: version "28.0.2" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-28.0.2.tgz#34622e628e4fdcd793d46db8a242227901fcf203" @@ -7210,6 +8154,11 @@ jest-get-type@^29.4.3: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.4.3.tgz#1ab7a5207c995161100b5187159ca82dd48b3dd5" integrity sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg== +jest-get-type@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" + integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== + jest-haste-map@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-28.1.3.tgz#abd5451129a38d9841049644f34b034308944e2b" @@ -7248,6 +8197,25 @@ jest-haste-map@^29.5.0: optionalDependencies: fsevents "^2.3.2" +jest-haste-map@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" + integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== + dependencies: + "@jest/types" "^29.6.3" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + jest-worker "^29.7.0" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + jest-leak-detector@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz#a6685d9b074be99e3adee816ce84fd30795e654d" @@ -7264,6 +8232,14 @@ jest-leak-detector@^29.5.0: jest-get-type "^29.4.3" pretty-format "^29.5.0" +jest-leak-detector@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" + integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== + dependencies: + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + jest-matcher-utils@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz#5a77f1c129dd5ba3b4d7fc20728806c78893146e" @@ -7284,6 +8260,16 @@ jest-matcher-utils@^29.5.0: jest-get-type "^29.4.3" pretty-format "^29.5.0" +jest-matcher-utils@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" + integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== + dependencies: + chalk "^4.0.0" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + jest-message-util@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-28.1.3.tgz#232def7f2e333f1eecc90649b5b94b0055e7c43d" @@ -7314,6 +8300,21 @@ jest-message-util@^29.5.0: slash "^3.0.0" stack-utils "^2.0.3" +jest-message-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" + integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.6.3" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + stack-utils "^2.0.3" + jest-mock@>=27, jest-mock@^29.5.0: version "29.5.0" resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.5.0.tgz#26e2172bcc71d8b0195081ff1f146ac7e1518aed" @@ -7331,6 +8332,15 @@ jest-mock@^28.1.3: "@jest/types" "^28.1.3" "@types/node" "*" +jest-mock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" + integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-util "^29.7.0" + jest-pnp-resolver@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" @@ -7346,6 +8356,11 @@ jest-regex-util@^29.4.3: resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.4.3.tgz#a42616141e0cae052cfa32c169945d00c0aa0bb8" integrity sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg== +jest-regex-util@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" + integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== + jest-resolve-dependencies@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.3.tgz#8c65d7583460df7275c6ea2791901fa975c1fe66" @@ -7362,6 +8377,14 @@ jest-resolve-dependencies@^29.5.0: jest-regex-util "^29.4.3" jest-snapshot "^29.5.0" +jest-resolve-dependencies@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" + integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== + dependencies: + jest-regex-util "^29.6.3" + jest-snapshot "^29.7.0" + jest-resolve@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-28.1.3.tgz#cfb36100341ddbb061ec781426b3c31eb51aa0a8" @@ -7392,6 +8415,21 @@ jest-resolve@^29.5.0: resolve.exports "^2.0.0" slash "^3.0.0" +jest-resolve@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" + integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-pnp-resolver "^1.2.2" + jest-util "^29.7.0" + jest-validate "^29.7.0" + resolve "^1.20.0" + resolve.exports "^2.0.0" + slash "^3.0.0" + jest-runner@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-28.1.3.tgz#5eee25febd730b4713a2cdfd76bdd5557840f9a1" @@ -7446,6 +8484,33 @@ jest-runner@^29.5.0: p-limit "^3.1.0" source-map-support "0.5.13" +jest-runner@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" + integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== + dependencies: + "@jest/console" "^29.7.0" + "@jest/environment" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.7.0" + jest-environment-node "^29.7.0" + jest-haste-map "^29.7.0" + jest-leak-detector "^29.7.0" + jest-message-util "^29.7.0" + jest-resolve "^29.7.0" + jest-runtime "^29.7.0" + jest-util "^29.7.0" + jest-watcher "^29.7.0" + jest-worker "^29.7.0" + p-limit "^3.1.0" + source-map-support "0.5.13" + jest-runtime@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-28.1.3.tgz#a57643458235aa53e8ec7821949e728960d0605f" @@ -7502,6 +8567,34 @@ jest-runtime@^29.5.0: slash "^3.0.0" strip-bom "^4.0.0" +jest-runtime@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" + integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/globals" "^29.7.0" + "@jest/source-map" "^29.6.3" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + strip-bom "^4.0.0" + jest-snapshot@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-28.1.3.tgz#17467b3ab8ddb81e2f605db05583d69388fc0668" @@ -7560,6 +8653,32 @@ jest-snapshot@^29.5.0: pretty-format "^29.5.0" semver "^7.3.5" +jest-snapshot@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" + integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^29.7.0" + graceful-fs "^4.2.9" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + natural-compare "^1.4.0" + pretty-format "^29.7.0" + semver "^7.5.3" + jest-util@>=27, jest-util@^29.0.0, jest-util@^29.5.0: version "29.5.0" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.5.0.tgz#24a4d3d92fc39ce90425311b23c27a6e0ef16b8f" @@ -7584,6 +8703,18 @@ jest-util@^28.0.0, jest-util@^28.1.3: graceful-fs "^4.2.9" picomatch "^2.2.3" +jest-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" + integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + jest-validate@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-28.1.3.tgz#e322267fd5e7c64cea4629612c357bbda96229df" @@ -7608,6 +8739,18 @@ jest-validate@^29.5.0: leven "^3.1.0" pretty-format "^29.5.0" +jest-validate@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" + integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== + dependencies: + "@jest/types" "^29.6.3" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^29.6.3" + leven "^3.1.0" + pretty-format "^29.7.0" + jest-watcher@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-28.1.3.tgz#c6023a59ba2255e3b4c57179fc94164b3e73abd4" @@ -7636,6 +8779,20 @@ jest-watcher@^29.5.0: jest-util "^29.5.0" string-length "^4.0.1" +jest-watcher@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" + integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== + dependencies: + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.13.1" + jest-util "^29.7.0" + string-length "^4.0.1" + jest-worker@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-28.1.3.tgz#7e3c4ce3fa23d1bb6accb169e7f396f98ed4bb98" @@ -7655,6 +8812,16 @@ jest-worker@^29.5.0: merge-stream "^2.0.0" supports-color "^8.0.0" +jest-worker@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" + integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== + dependencies: + "@types/node" "*" + jest-util "^29.7.0" + merge-stream "^2.0.0" + supports-color "^8.0.0" + jest@^28.1.2: version "28.1.3" resolved "https://registry.yarnpkg.com/jest/-/jest-28.1.3.tgz#e9c6a7eecdebe3548ca2b18894a50f45b36dfc6b" @@ -7675,6 +8842,16 @@ jest@^29.5.0: import-local "^3.0.2" jest-cli "^29.5.0" +jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" + integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== + dependencies: + "@jest/core" "^29.7.0" + "@jest/types" "^29.6.3" + import-local "^3.0.2" + jest-cli "^29.7.0" + jju@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/jju/-/jju-1.4.0.tgz#a3abe2718af241a2b2904f84a625970f389ae32a" @@ -7699,6 +8876,11 @@ js-cookie@3.0.1: resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-3.0.1.tgz#9e39b4c6c2f56563708d7d31f6f5f21873a92414" integrity sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw== +js-levenshtein@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d" + integrity sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g== + js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -7816,6 +8998,16 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== +json-stable-stringify@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.1.0.tgz#43d39c7c8da34bfaf785a61a56808b0def9f747d" + integrity sha512-zfA+5SuwYN2VWqN1/5HZaDzQKLJHaBVMZIIM+wuYjdptkaQsqzDdqjqf+lZZJUuJq1aanHiY8LhH8LmH+qBYJA== + dependencies: + call-bind "^1.0.5" + isarray "^2.0.5" + jsonify "^0.0.1" + object-keys "^1.1.1" + json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -7854,6 +9046,11 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" +jsonify@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.1.tgz#2aa3111dae3d34a0f151c63f3a45d995d9420978" + integrity sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg== + jsonwebtoken@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz#d0faf9ba1cc3a56255fe49c0961a67e520c1926d" @@ -7927,6 +9124,13 @@ kind-of@^6.0.3: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== +klaw-sync@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/klaw-sync/-/klaw-sync-6.0.0.tgz#1fd2cfd56ebb6250181114f0a581167099c2b28c" + integrity sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ== + dependencies: + graceful-fs "^4.1.11" + klaw@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/klaw/-/klaw-3.0.0.tgz#b11bec9cf2492f06756d6e809ab73a2910259146" @@ -9166,6 +10370,33 @@ ms@2.1.3, ms@^2.0.0, ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +msw@^2.0.4: + version "2.0.8" + resolved "https://registry.yarnpkg.com/msw/-/msw-2.0.8.tgz#de1153cac8030c33d19f6a1e14bb61221ec36d48" + integrity sha512-/5nQCotVka62lvubQ3tMfUS3TukyeBwvWyvAthcXvDlXGhkA/85HlEwZyFlJ3ZsPW45Ty+ao0S4oFvuM12R/kA== + dependencies: + "@bundled-es-modules/cookie" "^2.0.0" + "@bundled-es-modules/js-levenshtein" "^2.0.1" + "@bundled-es-modules/statuses" "^1.0.1" + "@mswjs/cookies" "^1.1.0" + "@mswjs/interceptors" "^0.25.11" + "@open-draft/until" "^2.1.0" + "@types/cookie" "^0.4.1" + "@types/js-levenshtein" "^1.1.1" + "@types/statuses" "^2.0.1" + chalk "^4.1.2" + chokidar "^3.4.2" + graphql "^16.8.1" + headers-polyfill "^4.0.1" + inquirer "^8.2.0" + is-node-process "^1.2.0" + js-levenshtein "^1.1.6" + outvariant "^1.4.0" + path-to-regexp "^6.2.0" + strict-event-emitter "^0.5.0" + type-fest "^2.19.0" + yargs "^17.3.1" + mustache@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/mustache/-/mustache-4.2.0.tgz#e5892324d60a12ec9c2a73359edca52972bf6f64" @@ -9608,7 +10839,7 @@ open@^6.3.0: dependencies: is-wsl "^1.1.0" -open@^7.3.0: +open@^7.3.0, open@^7.4.2: version "7.4.2" resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== @@ -9694,6 +10925,11 @@ outdent@^0.5.0: resolved "https://registry.yarnpkg.com/outdent/-/outdent-0.5.0.tgz#9e10982fdc41492bb473ad13840d22f9655be2ff" integrity sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q== +outvariant@^1.2.1, outvariant@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/outvariant/-/outvariant-1.4.0.tgz#e742e4bda77692da3eca698ef5bfac62d9fba06e" + integrity sha512-AlWY719RF02ujitly7Kk/0QlV+pXGFDHrHf9O2OKqyqgBieaPOIeuSkL8sRK6j2WK+/ZAURq2kZsY0d8JapUiw== + ow@^0.21.0: version "0.21.0" resolved "https://registry.yarnpkg.com/ow/-/ow-0.21.0.tgz#c2df2ad78d1bfc2ea9cdca311b7a6275258df621" @@ -9921,6 +11157,27 @@ parseurl@~1.3.3: resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== +patch-package@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-8.0.0.tgz#d191e2f1b6e06a4624a0116bcb88edd6714ede61" + integrity sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA== + dependencies: + "@yarnpkg/lockfile" "^1.1.0" + chalk "^4.1.2" + ci-info "^3.7.0" + cross-spawn "^7.0.3" + find-yarn-workspace-root "^2.0.0" + fs-extra "^9.0.0" + json-stable-stringify "^1.0.2" + klaw-sync "^6.0.0" + minimist "^1.2.6" + open "^7.4.2" + rimraf "^2.6.3" + semver "^7.5.3" + slash "^2.0.0" + tmp "^0.0.33" + yaml "^2.2.2" + path-depth@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/path-depth/-/path-depth-1.0.0.tgz#88cf881097e171b8b54d450d2167ea76063d3086" @@ -9976,6 +11233,11 @@ path-to-regexp@^1.8.0: dependencies: isarray "0.0.1" +path-to-regexp@^6.2.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.1.tgz#d54934d6798eb9e5ef14e7af7962c945906918e5" + integrity sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw== + path-type@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" @@ -10158,6 +11420,15 @@ pretty-format@^29.0.0, pretty-format@^29.5.0: ansi-styles "^5.0.0" react-is "^18.0.0" +pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + printable-characters@^1.0.42: version "1.0.42" resolved "https://registry.yarnpkg.com/printable-characters/-/printable-characters-1.0.42.tgz#3f18e977a9bd8eb37fcc4ff5659d7be90868b3d8" @@ -10742,6 +12013,13 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== +rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -10756,6 +12034,25 @@ rollup@^3.2.5, rollup@^3.27.1: optionalDependencies: fsevents "~2.3.2" +rollup@^4.0.2: + version "4.5.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.5.0.tgz#358ee6947fe0e4c8bacdae6896539cade3107655" + integrity sha512-41xsWhzxqjMDASCxH5ibw1mXk+3c4TNI2UjKbLxe6iEzrSQnqOzmmK8/3mufCPbzHNJ2e04Fc1ddI35hHy+8zg== + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.5.0" + "@rollup/rollup-android-arm64" "4.5.0" + "@rollup/rollup-darwin-arm64" "4.5.0" + "@rollup/rollup-darwin-x64" "4.5.0" + "@rollup/rollup-linux-arm-gnueabihf" "4.5.0" + "@rollup/rollup-linux-arm64-gnu" "4.5.0" + "@rollup/rollup-linux-arm64-musl" "4.5.0" + "@rollup/rollup-linux-x64-gnu" "4.5.0" + "@rollup/rollup-linux-x64-musl" "4.5.0" + "@rollup/rollup-win32-arm64-msvc" "4.5.0" + "@rollup/rollup-win32-ia32-msvc" "4.5.0" + "@rollup/rollup-win32-x64-msvc" "4.5.0" + fsevents "~2.3.2" + router@^1.3.1: version "1.3.8" resolved "https://registry.yarnpkg.com/router/-/router-1.3.8.tgz#1509614ae1fbc67139a728481c54b057ecfb04bf" @@ -10867,7 +12164,7 @@ semver-diff@^3.1.1: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@7.x, semver@^7.0.0, semver@^7.1.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.4: +semver@7.x, semver@^7.0.0, semver@^7.1.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== @@ -10918,6 +12215,16 @@ set-cookie-parser@^2.4.8: resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz#131921e50f62ff1a66a461d7d62d7b21d5d15a51" integrity sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ== +set-function-length@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed" + integrity sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ== + dependencies: + define-data-property "^1.1.1" + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + setprototypeof@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" @@ -11016,6 +12323,11 @@ sisteransi@^1.0.5: resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== +slash@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== + slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" @@ -11227,7 +12539,7 @@ stacktracey@^2.1.8: as-table "^1.0.36" get-source "^2.0.12" -statuses@2.0.1: +statuses@2.0.1, statuses@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== @@ -11284,6 +12596,11 @@ streamx@^2.15.0: fast-fifo "^1.1.0" queue-tick "^1.0.1" +strict-event-emitter@^0.5.0, strict-event-emitter@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz#1602ece81c51574ca39c6815e09f1a3e8550bd93" + integrity sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ== + string-length@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" @@ -11872,6 +13189,20 @@ ts-jest@^29.0.5: semver "7.x" yargs-parser "^21.0.1" +ts-jest@^29.1.1: + version "29.1.1" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.1.tgz#f58fe62c63caf7bfcc5cc6472082f79180f0815b" + integrity sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA== + dependencies: + bs-logger "0.x" + fast-json-stable-stringify "2.x" + jest-util "^29.0.0" + json5 "^2.2.3" + lodash.memoize "4.x" + make-error "1.x" + semver "^7.5.3" + yargs-parser "^21.0.1" + tsafe@^1.6.4: version "1.6.4" resolved "https://registry.yarnpkg.com/tsafe/-/tsafe-1.6.4.tgz#048a114761714538c72f16abd25bb247d4e3780e" @@ -11922,6 +13253,26 @@ tsup@^7.2.0: sucrase "^3.20.3" tree-kill "^1.2.2" +tsup@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/tsup/-/tsup-8.0.0.tgz#8e6c24c1ba88200ad54ab274259041b140dc1d59" + integrity sha512-9rOGn8LsFn2iAg2pCB1jnH7ygVuGjlzIomjw0jKXUxAii3iL5cXgm0jZMPKfFH1bSAjQovJ1DUVPSw+oDuIu8A== + dependencies: + bundle-require "^4.0.0" + cac "^6.7.12" + chokidar "^3.5.1" + debug "^4.3.1" + esbuild "^0.19.2" + execa "^5.0.0" + globby "^11.0.3" + joycon "^3.0.1" + postcss-load-config "^4.0.1" + resolve-from "^5.0.0" + rollup "^4.0.2" + source-map "0.8.0-beta.0" + sucrase "^3.20.3" + tree-kill "^1.2.2" + tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" @@ -12013,7 +13364,7 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== -type-fest@^2.5.2: +type-fest@^2.19.0, type-fest@^2.5.2: version "2.19.0" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==