diff --git a/.changeset/wild-glasses-own.md b/.changeset/wild-glasses-own.md new file mode 100644 index 00000000..a795e901 --- /dev/null +++ b/.changeset/wild-glasses-own.md @@ -0,0 +1,5 @@ +--- +'@hono/clerk-auth': major +--- + +Added Clerk Middleware diff --git a/.github/workflows/ci-clerk-auth.yml b/.github/workflows/ci-clerk-auth.yml new file mode 100644 index 00000000..58eebaea --- /dev/null +++ b/.github/workflows/ci-clerk-auth.yml @@ -0,0 +1,25 @@ +name: ci-clerk-auth +on: + push: + branches: [main] + paths: + - 'packages/clerk-auth/**' + pull_request: + branches: ['*'] + paths: + - 'packages/clerk-auth/**' + +jobs: + ci: + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./packages/clerk-auth + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: 18.x + - run: yarn install --frozen-lockfile + - run: yarn build + - run: yarn test diff --git a/package.json b/package.json index d209c801..acc9337c 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "build:sentry": "yarn workspace @hono/sentry build", "build:firebase-auth": "yarn workspace @hono/firebase-auth build", "build:trpc-server": "yarn workspace @hono/trpc-server build", + "build:clerk-auth": "yarn workspace @hono/clerk-auth build", "build:typebox-validator": "yarn workspace @hono/typebox-validator build", "build:medley-router": "yarn workspace @hono/medley-router build", "build:valibot-validator": "yarn workspace @hono/valibot-validator build", diff --git a/packages/clerk-auth/CHANGELOG.md b/packages/clerk-auth/CHANGELOG.md new file mode 100644 index 00000000..e69de29b diff --git a/packages/clerk-auth/README.md b/packages/clerk-auth/README.md new file mode 100644 index 00000000..1ff407b4 --- /dev/null +++ b/packages/clerk-auth/README.md @@ -0,0 +1,79 @@ +# Clerk middleware for Hono + +This is a [Clerk](https://clerk.com) third-party middleware for [Hono](https://github.com/honojs/hono). + +This middleware can be used to inject the active Clerk session into the request context. + +## Installation + +```plain +npm i hono @hono/clerk-auth @clerk/backend +``` + +## Configuration + +Before starting using the middleware you must set the following environment variables: + +```plain +CLERK_SECRET_KEY= +CLERK_PUBLISHABLE_KEY= +``` + +## How to Use + +```ts +import { clerkMiddleware, getAuth } from '@hono/clerk-auth' +import { Hono } from 'hono' + +const app = new Hono() + +app.use('*', clerkMiddleware()) +app.get('/', (c) => { + const auth = getAuth(c) + + if (!auth?.userId) { + return c.json({ + message: 'You are not logged in.' + }) + } + + return c.json({ + message: 'You are logged in!', + userId: auth.userId + }) +}) + +export default app +``` + +## Accessing instance of Backend API client + +```ts +import { clerkMiddleware, getAuth } from '@hono/clerk-auth' +import { Hono } from 'hono' + +const app = new Hono() + +app.use('*', clerkMiddleware()) +app.get('/', async (c) => { + const clerk = c.get('clerk') + + try { + const user = await clerkClient.users.getUser('user_id_....') + + return c.json({ + user, + }) + } catch (e) { + return c.json({ + message: 'User not found.' + }, 404) + } +}) + +export default app +``` + +## Author + +Vaggelis Yfantis diff --git a/packages/clerk-auth/jest.config.js b/packages/clerk-auth/jest.config.js new file mode 100644 index 00000000..c2e3e8a8 --- /dev/null +++ b/packages/clerk-auth/jest.config.js @@ -0,0 +1,12 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +module.exports = { + displayName: 'hono', + injectGlobals: true, + testMatch: ['**/test/**/*.+(ts|tsx|js)', '**/src/**/(*.)+(spec|test).+(ts|tsx|js)'], + transform: { '^.+\\.m?tsx?$': 'ts-jest' }, + testPathIgnorePatterns: ['/node_modules/', '/jest/'], + moduleNameMapper: { + '#crypto': '@clerk/backend/dist/runtime/node/crypto.js', + '#fetch': '@clerk/backend/dist/runtime/node/fetch.js', + }, +} diff --git a/packages/clerk-auth/package.json b/packages/clerk-auth/package.json new file mode 100644 index 00000000..cdb7ae29 --- /dev/null +++ b/packages/clerk-auth/package.json @@ -0,0 +1,36 @@ +{ + "name": "@hono/clerk-auth", + "version": "0.0.0", + "description": "A third-party Clerk auth middleware for Hono", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "test": "jest", + "build": "rimraf dist && tsc", + "prerelease": "yarn build && yarn test", + "release": "yarn publish" + }, + "license": "MIT", + "private": false, + "publishConfig": { + "registry": "https://registry.npmjs.org", + "access": "public" + }, + "repository": { + "type": "git", + "url": "https://github.com/honojs/middleware.git" + }, + "homepage": "https://github.com/honojs/middleware", + "peerDependencies": { + "@clerk/backend": "0.30.*", + "hono": "3.*" + }, + "devDependencies": { + "@clerk/backend": "^0.30.1", + "hono": "^3.7.3", + "node-fetch-native": "^1.4.0" + } +} diff --git a/packages/clerk-auth/src/index.ts b/packages/clerk-auth/src/index.ts new file mode 100644 index 00000000..a376ddbe --- /dev/null +++ b/packages/clerk-auth/src/index.ts @@ -0,0 +1,89 @@ +import type { ClerkOptions } from '@clerk/backend' +import { Clerk, createIsomorphicRequest, constants } from '@clerk/backend' +import type { Context, MiddlewareHandler } from 'hono' +import { env } from 'hono/adapter' + +type ClerkAuth = Awaited['authenticateRequest']>>['toAuth'] + +declare module 'hono' { + interface ContextVariableMap { + clerk: ReturnType + clerkAuth: ReturnType + } +} + +export const getAuth = (c: Context) => { + return c.get('clerkAuth') +} + +type ClerkEnv = { + CLERK_SECRET_KEY: string + CLERK_PUBLISHABLE_KEY: string + CLERK_API_URL: string + CLERK_API_VERSION: string + CLERK_FRONTEND_API: string +} + +export const clerkMiddleware = (options?: ClerkOptions): MiddlewareHandler => { + return async (c, next) => { + const clerkEnv = env(c) + const { secretKey, publishableKey, apiUrl, apiVersion, ...rest } = options || { + secretKey: clerkEnv.CLERK_SECRET_KEY || '', + publishableKey: clerkEnv.CLERK_PUBLISHABLE_KEY || '', + apiUrl: clerkEnv.CLERK_API_URL || 'https://api.clerk.dev', + apiVersion: clerkEnv.CLERK_API_VERSION || 'v1', + } + const frontendApi = clerkEnv.CLERK_FRONTEND_API || '' + if (!secretKey) { + throw new Error('Missing Clerk Secret key') + } + + if (!publishableKey) { + throw new Error('Missing Clerk Publishable key') + } + + const clerkClient = Clerk({ + ...rest, + apiUrl, + apiVersion, + secretKey, + publishableKey, + }) + + const requestState = await clerkClient.authenticateRequest({ + ...rest, + secretKey, + publishableKey, + request: createIsomorphicRequest((Request) => { + return new Request(c.req.url, { + method: c.req.method, + headers: c.req.raw.headers, + }) + }), + }) + + // Interstitial cases + if (requestState.isUnknown) { + c.header(constants.Headers.AuthReason, requestState.reason) + c.header(constants.Headers.AuthMessage, requestState.message) + return c.body(null, 401) + } + + if (requestState.isInterstitial) { + const interstitialHtmlPage = clerkClient.localInterstitial({ + publishableKey, + frontendApi, + }) + + c.header(constants.Headers.AuthReason, requestState.reason) + c.header(constants.Headers.AuthMessage, requestState.message) + + return c.html(interstitialHtmlPage, 401) + } + + c.set('clerkAuth', requestState.toAuth()) + c.set('clerk', clerkClient) + + await next() + } +} diff --git a/packages/clerk-auth/test/index.test.ts b/packages/clerk-auth/test/index.test.ts new file mode 100644 index 00000000..b84b992f --- /dev/null +++ b/packages/clerk-auth/test/index.test.ts @@ -0,0 +1,217 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { Hono } from 'hono' +import { clerkMiddleware, getAuth } from '../src' + +const EnvVariables = { + CLERK_SECRET_KEY: 'TEST_API_KEY', + CLERK_PUBLISHABLE_KEY: 'TEST_API_KEY', +} + +const authenticateRequestMock = jest.fn() +const localInterstitialMock = jest.fn() + +jest.mock('@clerk/backend', () => { + return { + ...jest.requireActual('@clerk/backend'), + Clerk: () => { + return { + authenticateRequest: (...args: any) => authenticateRequestMock(...args), + localInterstitial: (...args: any) => localInterstitialMock(...args), + } + }, + } +}) + +// Test are based on Clerk's test suite for Fastify plugin - https://github.com/clerkinc/javascript/blob/main/packages/fastify/src/withClerkMiddleware.test.ts +describe('clerkMiddleware()', () => { + beforeEach(() => { + process.env.CLERK_SECRET_KEY = EnvVariables.CLERK_SECRET_KEY + process.env.CLERK_PUBLISHABLE_KEY = EnvVariables.CLERK_PUBLISHABLE_KEY + jest.clearAllMocks() + jest.restoreAllMocks() + }) + + afterEach(() => { + jest.clearAllMocks() + }) + + test('handles signin with Authorization Bearer', async () => { + authenticateRequestMock.mockResolvedValue({ + isUnknown: false, + isInterstitial: false, + isSignedIn: true, + toAuth: () => 'mockedAuth', + }) + const app = new Hono() + app.use('*', clerkMiddleware()) + + app.get('/', (ctx) => { + const auth = getAuth(ctx) + return ctx.json({ auth }) + }) + + const req = new Request('http://localhost/', { + headers: { + Authorization: 'Bearer deadbeef', + Origin: 'http://origin.com', + Host: 'host.com', + 'X-Forwarded-Port': '1234', + 'X-Forwarded-Host': 'forwarded-host.com', + Referer: 'referer.com', + 'User-Agent': + 'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36', + }, + }) + + const response = await app.request(req) + + expect(response.status).toEqual(200) + expect(await response.json()).toEqual({ auth: 'mockedAuth' }) + expect(authenticateRequestMock).toBeCalledWith( + expect.objectContaining({ + secretKey: EnvVariables.CLERK_SECRET_KEY, + publishableKey: EnvVariables.CLERK_PUBLISHABLE_KEY, + request: expect.any(Request), + }) + ) + }) + + test('handles signin with cookie', async () => { + authenticateRequestMock.mockResolvedValue({ + isUnknown: false, + isInterstitial: false, + isSignedIn: true, + toAuth: () => 'mockedAuth', + }) + const app = new Hono() + app.use('*', clerkMiddleware()) + + app.get('/', (ctx) => { + const auth = getAuth(ctx) + return ctx.json({ auth }) + }) + + const req = new Request('http://localhost/', { + headers: { + cookie: '_gcl_au=value1; ko_id=value2; __session=deadbeef; __client_uat=1675692233', + Origin: 'http://origin.com', + Host: 'host.com', + 'X-Forwarded-Port': '1234', + 'X-Forwarded-Host': 'forwarded-host.com', + Referer: 'referer.com', + 'User-Agent': + 'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36', + }, + }) + + const response = await app.request(req) + + expect(response.status).toEqual(200) + expect(await response.json()).toEqual({ auth: 'mockedAuth' }) + expect(authenticateRequestMock).toBeCalledWith( + expect.objectContaining({ + secretKey: EnvVariables.CLERK_SECRET_KEY, + publishableKey: EnvVariables.CLERK_PUBLISHABLE_KEY, + request: expect.any(Request), + }) + ) + }) + + test('handles unknown case by terminating the request with empty response and 401 http code', async () => { + authenticateRequestMock.mockResolvedValue({ + isUnknown: true, + isInterstitial: false, + isSignedIn: false, + reason: 'auth-reason', + message: 'auth-message', + toAuth: () => 'mockedAuth', + }) + const app = new Hono() + app.use('*', clerkMiddleware()) + + app.get('/', (ctx) => { + const auth = getAuth(ctx) + return ctx.json({ auth }) + }) + + const req = new Request('http://localhost/', { + headers: { + cookie: '_gcl_au=value1; ko_id=value2; __session=deadbeef; __client_uat=1675692233', + }, + }) + + const response = await app.request(req) + + expect(response.status).toEqual(401) + expect(response.headers.get('x-clerk-auth-reason')).toEqual('auth-reason') + expect(response.headers.get('x-clerk-auth-message')).toEqual('auth-message') + expect(await response.text()).toEqual('') + }) + + test('handles interstitial case by terminating the request with interstitial html page and 401 http code', async () => { + authenticateRequestMock.mockResolvedValue({ + isUnknown: false, + isInterstitial: true, + isSignedIn: false, + reason: 'auth-reason', + message: 'auth-message', + toAuth: () => 'mockedAuth', + }) + localInterstitialMock.mockReturnValue('Interstitial') + const app = new Hono() + app.use('*', clerkMiddleware()) + + app.get('/', (ctx) => { + const auth = getAuth(ctx) + return ctx.json({ auth }) + }) + + const req = new Request('http://localhost/', { + headers: { + cookie: '_gcl_au=value1; ko_id=value2; __session=deadbeef; __client_uat=1675692233', + }, + }) + + const response = await app.request(req) + + expect(response.status).toEqual(401) + expect(response.headers.get('content-type')).toMatch('text/html') + expect(response.headers.get('x-clerk-auth-reason')).toEqual('auth-reason') + expect(response.headers.get('x-clerk-auth-message')).toEqual('auth-message') + expect(await response.text()).toEqual('Interstitial') + }) + + test('handles signout case by populating the req.auth', async () => { + authenticateRequestMock.mockResolvedValue({ + isUnknown: false, + isInterstitial: false, + isSignedIn: false, + toAuth: () => 'mockedAuth', + }) + const app = new Hono() + app.use('*', clerkMiddleware()) + + app.get('/', (ctx) => { + const auth = getAuth(ctx) + return ctx.json({ auth }) + }) + + const req = new Request('http://localhost/', { + headers: { + Authorization: 'Bearer deadbeef', + }, + }) + + const response = await app.request(req) + + expect(response.status).toEqual(200) + expect(await response.json()).toEqual({ auth: 'mockedAuth' }) + expect(authenticateRequestMock).toBeCalledWith( + expect.objectContaining({ + secretKey: EnvVariables.CLERK_SECRET_KEY, + publishableKey: EnvVariables.CLERK_PUBLISHABLE_KEY, + request: expect.any(Request), + }) + ) + }) +}) diff --git a/packages/clerk-auth/tsconfig.json b/packages/clerk-auth/tsconfig.json new file mode 100644 index 00000000..acfcd843 --- /dev/null +++ b/packages/clerk-auth/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/yarn.lock b/yarn.lock index 00e53d35..52f23dbe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -560,6 +560,27 @@ human-id "^1.0.2" prettier "^2.7.1" +"@clerk/backend@^0.30.1": + version "0.30.1" + resolved "https://registry.yarnpkg.com/@clerk/backend/-/backend-0.30.1.tgz#23179c68f0ce8a94d99bc2e8c5000cf896c8e577" + integrity sha512-+769bWE89Ejdy4ddu4wF/yBZypGVA5G/vAerJsXv/sdos3rSFtSghLx5OMdatn/2XqZUnrZoQGLtUz5ZxzDJXg== + dependencies: + "@clerk/types" "^3.53.0" + "@peculiar/webcrypto" "1.4.1" + "@types/node" "16.18.6" + cookie "0.5.0" + deepmerge "4.2.2" + node-fetch-native "1.0.1" + snakecase-keys "5.4.4" + tslib "2.4.1" + +"@clerk/types@^3.53.0": + version "3.53.0" + resolved "https://registry.yarnpkg.com/@clerk/types/-/types-3.53.0.tgz#5a7436e0ff89134401edafef7d50557e626a928f" + integrity sha512-V+9BvKAo9f2ShgP+RpQ/MgJTbx4ayk3sYiFbMtLYlmtLCsn0xwglfP7i++7640d6+MAtCnMTAcrTp61IvUxSFw== + dependencies: + csstype "3.1.1" + "@cloudflare/workers-types@^3.14.0", "@cloudflare/workers-types@^3.14.1": version "3.19.0" resolved "https://registry.yarnpkg.com/@cloudflare/workers-types/-/workers-types-3.19.0.tgz#f3791b80b23f7cf0072f2e67e98aa37801204b6c" @@ -1621,6 +1642,33 @@ resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.3.1.tgz#ba07b864a3c955f061aa30ea3ef7f4ae4449794a" integrity sha512-wU5J8rUoo32oSef/rFpOT1HIjLjAv3qIDHkw1QIhODV3OpAVHi5oVzlouozg9obUmZKtbZ0qUe/m7FP0y0yBzA== +"@peculiar/asn1-schema@^2.3.0", "@peculiar/asn1-schema@^2.3.6": + version "2.3.6" + resolved "https://registry.yarnpkg.com/@peculiar/asn1-schema/-/asn1-schema-2.3.6.tgz#3dd3c2ade7f702a9a94dfb395c192f5fa5d6b922" + integrity sha512-izNRxPoaeJeg/AyH8hER6s+H7p4itk+03QCa4sbxI3lNdseQYCuxzgsuNK8bTXChtLTjpJz6NmXKA73qLa3rCA== + dependencies: + asn1js "^3.0.5" + pvtsutils "^1.3.2" + tslib "^2.4.0" + +"@peculiar/json-schema@^1.1.12": + version "1.1.12" + resolved "https://registry.yarnpkg.com/@peculiar/json-schema/-/json-schema-1.1.12.tgz#fe61e85259e3b5ba5ad566cb62ca75b3d3cd5339" + integrity sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w== + dependencies: + tslib "^2.0.0" + +"@peculiar/webcrypto@1.4.1": + version "1.4.1" + resolved "https://registry.yarnpkg.com/@peculiar/webcrypto/-/webcrypto-1.4.1.tgz#821493bd5ad0f05939bd5f53b28536f68158360a" + integrity sha512-eK4C6WTNYxoI7JOabMoZICiyqRRtJB220bh0Mbj5RwRycleZf9BPyZoxsTvpP0FpmVS2aS13NKOuh5/tN3sIRw== + dependencies: + "@peculiar/asn1-schema" "^2.3.0" + "@peculiar/json-schema" "^1.1.12" + pvtsutils "^1.3.2" + tslib "^2.4.1" + webcrypto-core "^1.7.4" + "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" @@ -2093,6 +2141,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-20.3.1.tgz#e8a83f1aa8b649377bb1fb5d7bac5cb90e784dfe" integrity sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg== +"@types/node@16.18.6": + version "16.18.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.6.tgz#87846192fd51b693368fad3e99123169225621d4" + integrity sha512-vmYJF0REqDyyU0gviezF/KHq/fYaUbFhkcNbQCuPGFQj6VTbXuHZoxs/Y7mutWe73C8AC6l9fFu8mSYiBAqkGA== + "@types/node@^12.7.1": version "12.20.55" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" @@ -2636,6 +2689,15 @@ asn1@~0.2.3: dependencies: safer-buffer "~2.1.0" +asn1js@^3.0.1, asn1js@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/asn1js/-/asn1js-3.0.5.tgz#5ea36820443dbefb51cc7f88a2ebb5b462114f38" + integrity sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ== + dependencies: + pvtsutils "^1.3.2" + pvutils "^1.1.3" + tslib "^2.4.0" + assert-plus@1.0.0, assert-plus@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" @@ -3755,6 +3817,11 @@ csso@^5.0.5: dependencies: css-tree "~2.2.0" +csstype@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9" + integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw== + csstype@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b" @@ -3908,6 +3975,11 @@ deep-is@^0.1.3, deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== +deepmerge@4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + deepmerge@^4.2.2: version "4.3.1" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" @@ -4117,6 +4189,14 @@ domutils@^3.0.1: domelementtype "^2.3.0" domhandler "^5.0.3" +dot-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" + integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + dot-prop@^5.2.0: version "5.3.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" @@ -5869,6 +5949,11 @@ hono@^3.5.8: resolved "https://registry.yarnpkg.com/hono/-/hono-3.5.8.tgz#9bbc412f5a54183cf2a81a36a9b9ea56da10f785" integrity sha512-ZipTmGfHm43q5QOEBGog2wyejyNUcicjPt0BLDQ8yz9xij/y9RYXRpR1YPxMpQqeyNM7isvpsIAe9Ems51Wq0Q== +hono@^3.7.3: + version "3.7.3" + resolved "https://registry.yarnpkg.com/hono/-/hono-3.7.3.tgz#01fd88360e9a431235110197fbb5a998131e104e" + integrity sha512-BQHdLPXb30hQ9k+04byeSi4QMHk20U1GUq0nT5kGUCGZtxeYhAS7mUJ1wgjn4SCvgiw1rcc6oBOAlwJQ7jQymA== + hono@^3.7.2: version "3.7.2" resolved "https://registry.yarnpkg.com/hono/-/hono-3.7.2.tgz#c3839d7ffbb5120850b2b926363d065020f4d18c" @@ -8003,6 +8088,13 @@ loupe@^2.3.1, loupe@^2.3.6: dependencies: get-func-name "^2.0.0" +lower-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== + dependencies: + tslib "^2.0.3" + lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" @@ -8104,7 +8196,7 @@ map-obj@^1.0.0: resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" integrity sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg== -map-obj@^4.0.0: +map-obj@^4.0.0, map-obj@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a" integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== @@ -8945,6 +9037,14 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== +no-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== + dependencies: + lower-case "^2.0.2" + tslib "^2.0.3" + node-abi@^3.3.0: version "3.47.0" resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.47.0.tgz#6cbfa2916805ae25c2b7156ca640131632eb05e8" @@ -8964,6 +9064,16 @@ node-emoji@^1.11.0: dependencies: lodash "^4.17.21" +node-fetch-native@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.0.1.tgz#1dfe78f57545d07e07016b7df4c0cb9d2ff416c7" + integrity sha512-VzW+TAk2wE4X9maiKMlT+GsPU4OMmR1U9CrHSmd3DFLn2IcZ9VJ6M6BBugGfYUnPCLSYxXdZy17M0BEJyhUTwg== + +node-fetch-native@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.4.0.tgz#fbe8ac033cb6aa44bd106b5e4fd2b6277ba70fa1" + integrity sha512-F5kfEj95kX8tkDhUCYdV8dg3/8Olx/94zB8+ZNthFs6Bz31UpUi8Xh40TN3thLwXgrwXry1pEg9lJ++tLWTcqA== + node-fetch@^2.5.0, node-fetch@^2.6.1, node-fetch@^2.6.7, node-fetch@^2.6.9: version "2.6.11" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.11.tgz#cde7fc71deef3131ef80a738919f999e6edfff25" @@ -10006,6 +10116,18 @@ pure-rand@^6.0.0: resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.2.tgz#a9c2ddcae9b68d736a8163036f088a2781c8b306" integrity sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ== +pvtsutils@^1.3.2: + version "1.3.5" + resolved "https://registry.yarnpkg.com/pvtsutils/-/pvtsutils-1.3.5.tgz#b8705b437b7b134cd7fd858f025a23456f1ce910" + integrity sha512-ARvb14YB9Nm2Xi6nBq1ZX6dAM0FsJnuk+31aUp4TrcZEdKUlSqOqsxJHUPJDNE3qiIp+iUPEIeR6Je/tgV7zsA== + dependencies: + tslib "^2.6.1" + +pvutils@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/pvutils/-/pvutils-1.1.3.tgz#f35fc1d27e7cd3dfbd39c0826d173e806a03f5a3" + integrity sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ== + qs@6.11.0: version "6.11.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" @@ -10728,6 +10850,23 @@ smartwrap@^2.0.2: wcwidth "^1.0.1" yargs "^15.1.0" +snake-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c" + integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + +snakecase-keys@5.4.4: + version "5.4.4" + resolved "https://registry.yarnpkg.com/snakecase-keys/-/snakecase-keys-5.4.4.tgz#28745b0175863ffc292ad97d96fe4e8e288a87a2" + integrity sha512-YTywJG93yxwHLgrYLZjlC75moVEX04LZM4FHfihjHe1FCXm+QaLOFfSf535aXOAd0ArVQMWUAe8ZPm4VtWyXaA== + dependencies: + map-obj "^4.1.0" + snake-case "^3.0.4" + type-fest "^2.5.2" + socks-proxy-agent@5, socks-proxy-agent@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz#032fb583048a29ebffec2e6a73fca0761f48177e" @@ -11522,21 +11661,26 @@ tsconfig-paths@^3.14.1: minimist "^1.2.6" strip-bom "^3.0.0" +tslib@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" + integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== + tslib@^1.8.1, tslib@^1.9.0: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +tslib@^2.0.0, tslib@^2.0.3, tslib@^2.4.0, tslib@^2.4.1, "tslib@^2.4.1 || ^1.9.3", tslib@^2.6.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + tslib@^2.0.1, tslib@^2.1.0, tslib@^2.5.0: version "2.5.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.3.tgz#24944ba2d990940e6e982c4bea147aba80209913" integrity sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w== -"tslib@^2.4.1 || ^1.9.3": - version "2.6.2" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" - integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== - tsup@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/tsup/-/tsup-7.2.0.tgz#bb24c0d5e436477900c712e42adc67200607303c" @@ -11648,6 +11792,11 @@ 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: + version "2.19.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" + integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== + type-fest@^3.0.0: version "3.12.0" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-3.12.0.tgz#4ce26edc1ccc59fc171e495887ef391fe1f5280e" @@ -12148,6 +12297,17 @@ wcwidth@^1.0.1: dependencies: defaults "^1.0.3" +webcrypto-core@^1.7.4: + version "1.7.7" + resolved "https://registry.yarnpkg.com/webcrypto-core/-/webcrypto-core-1.7.7.tgz#06f24b3498463e570fed64d7cab149e5437b162c" + integrity sha512-7FjigXNsBfopEj+5DV2nhNpfic2vumtjjgPmeDKk45z+MJwXKKfhPB7118Pfzrmh4jqOMST6Ch37iPAHoImg5g== + dependencies: + "@peculiar/asn1-schema" "^2.3.6" + "@peculiar/json-schema" "^1.1.12" + asn1js "^3.0.1" + pvtsutils "^1.3.2" + tslib "^2.4.0" + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"