diff --git a/.github/workflows/on-pr.yml b/.github/workflows/on-pr.yml index 5c114ef4f63..36a24de03b4 100644 --- a/.github/workflows/on-pr.yml +++ b/.github/workflows/on-pr.yml @@ -237,10 +237,11 @@ jobs: strategy: # The order is important for ee to be first, otherwise outputs not work correctly matrix: - name: ['novu/api-ee', 'novu/api'] + name: ['novu/api-ee', 'novu/api', 'novu/api-ee-clerk'] uses: ./.github/workflows/reusable-api-e2e.yml with: ee: ${{ contains (matrix.name,'-ee') }} + ee-clerk: ${{ contains (matrix.name,'-ee-clerk') }} test-e2e-affected: ${{ contains(fromJson(needs.get-affected.outputs.test-e2e), '@novu/api') }} test-e2e-ee-affected: ${{ contains(fromJson(needs.get-affected.outputs.test-e2e-ee), '@novu/api') }} job-name: ${{ matrix.name }} diff --git a/.github/workflows/reusable-api-e2e.yml b/.github/workflows/reusable-api-e2e.yml index f3dd9ef896d..4192ef39512 100644 --- a/.github/workflows/reusable-api-e2e.yml +++ b/.github/workflows/reusable-api-e2e.yml @@ -19,8 +19,13 @@ on: required: false default: false type: boolean + ee-clerk: + description: 'use the clerk ee version of api' + required: false + default: false + type: boolean job-name: - description: 'job name [options: novu/api-ee, novu/api]' + description: 'job name [options: novu/api-ee, novu/api, novu/api-ee-clerk]' required: true type: string @@ -97,7 +102,7 @@ jobs: cd apps/api && pnpm test:e2e - name: Run E2E EE tests - if: ${{ needs.check_submodule_token.outputs.has_token == 'true' && inputs.ee }} + if: ${{ needs.check_submodule_token.outputs.has_token == 'true' && inputs.ee && !inputs.ee-clerk }} env: LAUNCH_DARKLY_SDK_KEY: ${{ secrets.LAUNCH_DARKLY_SDK_KEY }} GOOGLE_OAUTH_CLIENT_ID: ${{ secrets.GOOGLE_OAUTH_CLIENT_ID }} @@ -106,6 +111,25 @@ jobs: run: | cd apps/api && pnpm test:e2e:ee + - name: Run E2E EE Clerk tests + if: ${{ needs.check_submodule_token.outputs.has_token == 'true' && inputs.ee && inputs.ee-clerk }} + env: + LAUNCH_DARKLY_SDK_KEY: ${{ secrets.LAUNCH_DARKLY_SDK_KEY }} + GOOGLE_OAUTH_CLIENT_ID: ${{ secrets.GOOGLE_OAUTH_CLIENT_ID }} + GOOGLE_OAUTH_CLIENT_SECRET: ${{ secrets.GOOGLE_OAUTH_CLIENT_SECRET }} + CI_EE_TEST: true + CLERK_ENABLED: true + CLERK_ISSUER_URL: ${{ vars.CLERK_ISSUER_URL }} + CLERK_SECRET_KEY: ${{ secrets.CLERK_SECRET_KEY }} + CLERK_PRIVATE_KEY_BASE64: ${{ secrets.CLERK_PRIVATE_KEY_BASE64 }} + CLERK_PEM_PUBLIC_KEY_BASE64: ${{ secrets.CLERK_PEM_PUBLIC_KEY_BASE64 }} + WEBHOOK_SECRET: ${{ secrets.WEBHOOK_SECRET }} + CLERK_LONG_LIVED_TOKEN: ${{ secrets.CLERK_LONG_LIVED_TOKEN }} + run: | + export CLERK_PEM_PUBLIC_KEY=$(echo $CLERK_PEM_PUBLIC_KEY_BASE64 | base64 -d) + export CLERK_PRIVATE_KEY=$(echo $CLERK_PRIVATE_KEY_BASE64 | base64 -d) + cd apps/api && pnpm test:e2e:clerk + - name: Kill port for worker 1342 for unit tests run: sudo kill -9 $(sudo lsof -t -i:1342) diff --git a/.source b/.source index 97fae674753..51c9b1628dc 160000 --- a/.source +++ b/.source @@ -1 +1 @@ -Subproject commit 97fae6747534f2edd74d91599ffcb6af90524e75 +Subproject commit 51c9b1628dc53d5bb4d8e2c5025e19ecdf795d2f diff --git a/apps/api/e2e/setup.ts b/apps/api/e2e/setup.ts index e30097254eb..ee8c770184f 100644 --- a/apps/api/e2e/setup.ts +++ b/apps/api/e2e/setup.ts @@ -4,9 +4,23 @@ import sinon from 'sinon'; import chai from 'chai'; import { bootstrap } from '../src/bootstrap'; +import { isClerkEnabled } from '@novu/shared'; const dalService = new DalService(); +async function seedClerkMongo() { + if (isClerkEnabled()) { + const clerkClientMock = require('@novu/ee-auth')?.ClerkClientMock; + + if (clerkClientMock) { + const clerkClient = new clerkClientMock(); + await clerkClient.seedDatabase(); + } else { + throw new Error('ClerkClientMock not found'); + } + } +} + before(async () => { /** * disable truncating for better error messages - https://www.chaijs.com/guide/styles/#configtruncatethreshold @@ -15,6 +29,7 @@ before(async () => { await testServer.create(await bootstrap()); await dalService.connect(process.env.MONGO_URL); + await seedClerkMongo(); }); after(async () => { diff --git a/apps/api/package.json b/apps/api/package.json index ff4d8896fec..2991d2231de 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -20,9 +20,13 @@ "lint:fix": "pnpm lint -- --fix", "lint:openapi": "spectral lint http://127.0.0.1:${PORT:-3000}/openapi.yaml", "test": "cross-env TS_NODE_COMPILER_OPTIONS='{\"strictNullChecks\": false}' NODE_ENV=test E2E_RUNNER=true mocha --require ts-node/register --exit --file e2e/setup.ts src/**/**/*.spec.ts", - "test:e2e": "cross-env TS_NODE_COMPILER_OPTIONS='{\"strictNullChecks\": false}' NODE_ENV=test E2E_RUNNER=true mocha --require ts-node/register --exit --file e2e/setup.ts src/**/*.e2e.ts", + "test:e2e": "cross-env TS_NODE_COMPILER_OPTIONS='{\"strictNullChecks\": false}' NODE_ENV=test E2E_RUNNER=true mocha --require ts-node/register --exit --file e2e/setup.ts src/**/*.e2e.ts ", "test:e2e:ee": "cross-env TS_NODE_COMPILER_OPTIONS='{\"strictNullChecks\": false}' NODE_ENV=test E2E_RUNNER=true CI_EE_TEST=true mocha --require ts-node/register --exit --file e2e/setup.ts src/**/*.e2e-ee.ts", - "migration": "cross-env NODE_ENV=local MIGRATION=true ts-node --transpileOnly" + "test:e2e:clerk": "cross-env TS_NODE_COMPILER_OPTIONS='{\"strictNullChecks\": false}' NODE_ENV=test E2E_RUNNER=true CI_EE_TEST=true CLERK_ENABLED=true mocha --grep @skip-in-ee --invert --require ts-node/register --exit --file e2e/setup.ts 'src/**/*.e2e{,-ee}.ts'", + "migration": "cross-env NODE_ENV=local MIGRATION=true ts-node --transpileOnly", + "link:submodules": "pnpm link ../../enterprise/packages/auth && pnpm link ../../enterprise/packages/translation && pnpm link ../../enterprise/packages/billing", + "admin:remove-user-account": "cross-env NODE_ENV=local MIGRATION=true ts-node --transpileOnly ./admin/remove-user-account.ts", + "admin:remove-organization": "cross-env NODE_ENV=local MIGRATION=true ts-node --transpileOnly ./admin/remove-organization.ts" }, "dependencies": { "@godaddy/terminus": "^4.12.1", @@ -53,7 +57,6 @@ "bcrypt": "^5.0.0", "body-parser": "^1.20.0", "bull": "^4.2.1", - "nimma": "^0.6.0", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "compression": "^1.7.4", @@ -71,8 +74,10 @@ "nanoid": "^3.1.20", "nest-raven": "^10.0.0", "newrelic": "^9.15.0", + "nimma": "^0.6.0", "passport": "0.6.0", "passport-github2": "^0.1.12", + "passport-google-oauth": "^2.0.0", "passport-headerapikey": "^1.2.2", "passport-jwt": "^4.0.0", "passport-oauth2": "^1.6.1", diff --git a/apps/api/src/.env.development b/apps/api/src/.env.development index 95391d5c401..032f00f713f 100644 --- a/apps/api/src/.env.development +++ b/apps/api/src/.env.development @@ -84,3 +84,6 @@ PR_PREVIEW_ROOT_URL=dev-web-novu.netlify.app HUBSPOT_INVITE_NUDGE_EMAIL_USER_LIST_ID= HUBSPOT_PRIVATE_APP_ACCESS_TOKEN= + +CLERK_ISSUER_URL= +WEBHOOK_SECRET= \ No newline at end of file diff --git a/apps/api/src/.env.production b/apps/api/src/.env.production index 44826714dc2..05ecb1270ec 100644 --- a/apps/api/src/.env.production +++ b/apps/api/src/.env.production @@ -72,3 +72,6 @@ API_RATE_LIMIT_MAXIMUM_UNLIMITED_GLOBAL= HUBSPOT_INVITE_NUDGE_EMAIL_USER_LIST_ID= HUBSPOT_PRIVATE_APP_ACCESS_TOKEN= + +CLERK_ISSUER_URL= +WEBHOOK_SECRET= diff --git a/apps/api/src/.env.test b/apps/api/src/.env.test index e2d256f730b..b75ca7d4649 100644 --- a/apps/api/src/.env.test +++ b/apps/api/src/.env.test @@ -111,4 +111,10 @@ IS_USE_MERGED_DIGEST_ID_ENABLED=true HUBSPOT_INVITE_NUDGE_EMAIL_USER_LIST_ID= HUBSPOT_PRIVATE_APP_ACCESS_TOKEN= +CLERK_ISSUER_URL= +CLERK_LONG_LIVED_TOKEN= + +CLERK_PRIVATE_KEY= +CLERK_PEM_PUBLIC_KEY= + TUNNEL_BASE_ADDRESS=example.com diff --git a/apps/api/src/.example.env b/apps/api/src/.example.env index 6b25cf1fd4d..21affbfbe90 100644 --- a/apps/api/src/.example.env +++ b/apps/api/src/.example.env @@ -79,4 +79,7 @@ API_RATE_LIMIT_MAXIMUM_UNLIMITED_GLOBAL= HUBSPOT_INVITE_NUDGE_EMAIL_USER_LIST_ID= HUBSPOT_PRIVATE_APP_ACCESS_TOKEN= +CLERK_ISSUER_URL= +CLERK_LONG_LIVED_TOKEN= + TUNNEL_BASE_ADDRESS= diff --git a/apps/api/src/app.module.ts b/apps/api/src/app.module.ts index 3b479fc13c9..de40a6f2e71 100644 --- a/apps/api/src/app.module.ts +++ b/apps/api/src/app.module.ts @@ -39,13 +39,17 @@ import { RateLimitingModule } from './app/rate-limiting/rate-limiting.module'; import { ProductFeatureInterceptor } from './app/shared/interceptors/product-feature.interceptor'; import { AnalyticsModule } from './app/analytics/analytics.module'; import { InboxModule } from './app/inbox/inbox.module'; +import { isClerkEnabled } from '@novu/shared'; +import { LegacyEEAuthModule } from './app/auth/legacy-ee-auth/auth.module'; const enterpriseImports = (): Array | ForwardReference> => { const modules: Array | ForwardReference> = []; if (process.env.NOVU_ENTERPRISE === 'true' || process.env.CI_EE_TEST === 'true') { - if (require('@novu/ee-auth')?.EEAuthModule) { - modules.push(require('@novu/ee-auth')?.EEAuthModule); + // TODO: remove after Clerk replaces legacy EE auth + if (process.env.CLERK_ENABLED !== 'true') { + modules.push(LegacyEEAuthModule); } + if (require('@novu/ee-bridge-api')?.BridgeModule) { modules.push(require('@novu/ee-bridge-api')?.BridgeModule); } @@ -57,6 +61,12 @@ const enterpriseImports = (): Array | ForwardReference> = [ + AuthModule, InboundParseModule, - OrganizationModule, SharedModule, - UserModule, - AuthModule, HealthModule, EnvironmentsModule, ExecutionDetailsModule, @@ -85,10 +93,10 @@ const baseModules: Array | Forward WidgetsModule, InboxModule, NotificationModule, - StorageModule, NotificationGroupsModule, - InvitesModule, ContentTemplatesModule, + OrganizationModule, + UserModule, IntegrationModule, ChangeModule, SubscribersModule, @@ -101,12 +109,18 @@ const baseModules: Array | Forward TenantModule, WorkflowOverridesModule, RateLimitingModule, + WidgetsModule, ProfilingModule.register(packageJson.name), TracingModule.register(packageJson.name, packageJson.version), ]; const enterpriseModules = enterpriseImports(); +if (!isClerkEnabled()) { + const communityModules = [StorageModule, InvitesModule]; + baseModules.push(...communityModules); +} + const modules = baseModules.concat(enterpriseModules); const providers: Provider[] = [ diff --git a/apps/api/src/app/auth/auth.module.ts b/apps/api/src/app/auth/auth.module.ts index 83a421ff7a5..4f4e9935b51 100644 --- a/apps/api/src/app/auth/auth.module.ts +++ b/apps/api/src/app/auth/auth.module.ts @@ -1,65 +1,24 @@ -import { MiddlewareConsumer, Module, NestModule, Provider, RequestMethod } from '@nestjs/common'; -import { JwtModule } from '@nestjs/jwt'; -import { PassportModule } from '@nestjs/passport'; -const passport = require('passport'); +import { Global, MiddlewareConsumer, Module, ModuleMetadata } from '@nestjs/common'; +import { isClerkEnabled } from '@novu/shared'; +import { getCommunityAuthModuleConfig, configure as configureCommunity } from './community.auth.module.config'; +import { getEEModuleConfig, configure as configureEE } from './ee.auth.module.config'; -import { AuthProviderEnum, PassportStrategyEnum } from '@novu/shared'; -import { AuthService } from '@novu/application-generic'; - -import { RolesGuard } from './framework/roles.guard'; -import { JwtStrategy } from './services/passport/jwt.strategy'; -import { AuthController } from './auth.controller'; -import { UserModule } from '../user/user.module'; -import { USE_CASES } from './usecases'; -import { SharedModule } from '../shared/shared.module'; -import { GitHubStrategy } from './services/passport/github.strategy'; -import { OrganizationModule } from '../organization/organization.module'; -import { EnvironmentsModule } from '../environments/environments.module'; -import { JwtSubscriberStrategy } from './services/passport/subscriber-jwt.strategy'; -import { UserAuthGuard } from './framework/user.auth.guard'; -import { RootEnvironmentGuard } from './framework/root-environment-guard.service'; -import { ApiKeyStrategy } from './services/passport/apikey.strategy'; - -const AUTH_STRATEGIES: Provider[] = [JwtStrategy, ApiKeyStrategy, JwtSubscriberStrategy]; - -if (process.env.GITHUB_OAUTH_CLIENT_ID) { - AUTH_STRATEGIES.push(GitHubStrategy); +function getModuleConfig(): ModuleMetadata { + if (isClerkEnabled()) { + return getEEModuleConfig(); + } else { + return getCommunityAuthModuleConfig(); + } } -@Module({ - imports: [ - OrganizationModule, - SharedModule, - UserModule, - PassportModule.register({ - defaultStrategy: PassportStrategyEnum.JWT, - }), - JwtModule.register({ - secretOrKeyProvider: () => process.env.JWT_SECRET as string, - signOptions: { - expiresIn: 360000, - }, - }), - EnvironmentsModule, - ], - controllers: [AuthController], - providers: [UserAuthGuard, ...USE_CASES, ...AUTH_STRATEGIES, AuthService, RolesGuard, RootEnvironmentGuard], - exports: [RolesGuard, RootEnvironmentGuard, AuthService, ...USE_CASES, UserAuthGuard], -}) -export class AuthModule implements NestModule { +@Global() +@Module(getModuleConfig()) +export class AuthModule { public configure(consumer: MiddlewareConsumer) { - if (process.env.GITHUB_OAUTH_CLIENT_ID) { - consumer - .apply( - passport.authenticate(AuthProviderEnum.GITHUB, { - session: false, - scope: ['user:email'], - }) - ) - .forRoutes({ - path: '/auth/github', - method: RequestMethod.GET, - }); + if (isClerkEnabled()) { + configureEE(consumer); + } else { + configureCommunity(consumer); } } } diff --git a/apps/api/src/app/auth/community.auth.module.config.ts b/apps/api/src/app/auth/community.auth.module.config.ts new file mode 100644 index 00000000000..b2c2708593a --- /dev/null +++ b/apps/api/src/app/auth/community.auth.module.config.ts @@ -0,0 +1,83 @@ +import { MiddlewareConsumer, ModuleMetadata, Provider, RequestMethod } from '@nestjs/common'; +import { JwtModule } from '@nestjs/jwt'; +import { PassportModule } from '@nestjs/passport'; +import passport from 'passport'; + +import { AuthProviderEnum, PassportStrategyEnum } from '@novu/shared'; +import { AuthService } from '@novu/application-generic'; + +import { RolesGuard } from './framework/roles.guard'; +import { JwtStrategy } from './services/passport/jwt.strategy'; +import { AuthController } from './auth.controller'; +import { UserModule } from '../user/user.module'; +import { USE_CASES } from './usecases'; +import { SharedModule } from '../shared/shared.module'; +import { GitHubStrategy } from './services/passport/github.strategy'; +import { OrganizationModule } from '../organization/organization.module'; +import { EnvironmentsModule } from '../environments/environments.module'; +import { JwtSubscriberStrategy } from './services/passport/subscriber-jwt.strategy'; +import { RootEnvironmentGuard } from './framework/root-environment-guard.service'; +import { ApiKeyStrategy } from './services/passport/apikey.strategy'; +import { injectRepositories } from '@novu/application-generic'; + +const AUTH_STRATEGIES: Provider[] = [JwtStrategy, ApiKeyStrategy, JwtSubscriberStrategy]; + +if (process.env.GITHUB_OAUTH_CLIENT_ID) { + AUTH_STRATEGIES.push(GitHubStrategy); +} + +export function getCommunityAuthModuleConfig(): ModuleMetadata { + return { + imports: [ + OrganizationModule, + SharedModule, + UserModule, + PassportModule.register({ + defaultStrategy: PassportStrategyEnum.JWT, + }), + JwtModule.register({ + secret: process.env.JWT_SECRET, + signOptions: { + expiresIn: 360000, + }, + }), + EnvironmentsModule, + ], + controllers: [AuthController], + providers: [ + ...USE_CASES, + ...AUTH_STRATEGIES, + ...injectRepositories({ repositoriesOnly: false }), + AuthService, + RolesGuard, + RootEnvironmentGuard, + ], + exports: [ + RolesGuard, + RootEnvironmentGuard, + AuthService, + 'AUTH_SERVICE', + 'USER_AUTH_GUARD', + 'USER_REPOSITORY', + 'MEMBER_REPOSITORY', + 'ORGANIZATION_REPOSITORY', + ...USE_CASES, + ], + }; +} + +export function configure(consumer: MiddlewareConsumer) { + if (process.env.GITHUB_OAUTH_CLIENT_ID) { + consumer + .apply( + passport.authenticate(AuthProviderEnum.GITHUB, { + session: false, + scope: ['user:email'], + }) + ) + .forRoutes({ + path: '/auth/github', + method: RequestMethod.GET, + }); + } +} diff --git a/apps/api/src/app/auth/e2e/login.e2e.ts b/apps/api/src/app/auth/e2e/login.e2e.ts index 34216022ad3..2af4c15c4db 100644 --- a/apps/api/src/app/auth/e2e/login.e2e.ts +++ b/apps/api/src/app/auth/e2e/login.e2e.ts @@ -2,12 +2,12 @@ import { UserSession } from '@novu/testing'; import jwt from 'jsonwebtoken'; import { subMinutes } from 'date-fns'; import { expect } from 'chai'; +import { CommunityUserRepository } from '@novu/dal'; import { UserSessionData } from '@novu/shared'; -import { UserRepository } from '@novu/dal'; -describe('User login - /auth/login (POST)', async () => { +describe('User login - /auth/login (POST) @skip-in-ee', async () => { let session: UserSession; - const userRepository = new UserRepository(); + const userRepository = new CommunityUserRepository(); const userCredentials = { email: 'Testy.test22@gmail.com', password: '123Qwerty@', diff --git a/apps/api/src/app/auth/e2e/oauth.e2e-ee.ts b/apps/api/src/app/auth/e2e/oauth.e2e-ee.ts deleted file mode 100644 index d3189adc0cf..00000000000 --- a/apps/api/src/app/auth/e2e/oauth.e2e-ee.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { UserSession } from '@novu/testing'; -import { expect } from 'chai'; - -describe('User login - /auth/google (GET)', async () => { - let session: UserSession; - - before(async () => { - session = new UserSession(); - await session.initialize(); - }); - - it('should redirect to google oauth', async () => { - const res = await session.testAgent.get('/v1/auth/google').send(); - - expect(res.statusCode).to.equal(302); - expect(res.headers.location).to.contain('accounts.google.com/o/oauth2/v2/auth'); - }); -}); diff --git a/apps/api/src/app/auth/e2e/password-reset.e2e.ts b/apps/api/src/app/auth/e2e/password-reset.e2e.ts index 4097213fbc5..9122a4b1a93 100644 --- a/apps/api/src/app/auth/e2e/password-reset.e2e.ts +++ b/apps/api/src/app/auth/e2e/password-reset.e2e.ts @@ -1,4 +1,4 @@ -import { UserRepository } from '@novu/dal'; +import { CommunityUserRepository } from '@novu/dal'; import { UserSession } from '@novu/testing'; import { v4 as uuidv4 } from 'uuid'; import { expect } from 'chai'; @@ -6,9 +6,9 @@ import { stub, SinonStubbedMember } from 'sinon'; import { subDays, subMinutes } from 'date-fns'; import { PasswordResetFlowEnum } from '@novu/shared'; -describe('Password reset - /auth/reset (POST)', async () => { +describe('Password reset - /auth/reset (POST) @skip-in-ee', async () => { let session: UserSession; - const userRepository = new UserRepository(); + const userRepository = new CommunityUserRepository(); const requestResetToken = async (payload) => { let plainToken: string; @@ -16,11 +16,11 @@ describe('Password reset - /auth/reset (POST)', async () => { * Wrapper for method to obtain plain reset token before hashing. * Stub is created on Prototype because API and tests use different UserRepository instances. */ - stub(UserRepository.prototype, 'updatePasswordResetToken').callsFake((...args) => { + stub(CommunityUserRepository.prototype, 'updatePasswordResetToken').callsFake((...args) => { plainToken = args[1]; ( - UserRepository.prototype.updatePasswordResetToken as SinonStubbedMember< - typeof UserRepository.prototype.updatePasswordResetToken + CommunityUserRepository.prototype.updatePasswordResetToken as SinonStubbedMember< + typeof CommunityUserRepository.prototype.updatePasswordResetToken > ).restore(); diff --git a/apps/api/src/app/auth/e2e/switch-environment.e2e.ts b/apps/api/src/app/auth/e2e/switch-environment.e2e.ts index 09ebcbaaa59..0f050fa97b8 100644 --- a/apps/api/src/app/auth/e2e/switch-environment.e2e.ts +++ b/apps/api/src/app/auth/e2e/switch-environment.e2e.ts @@ -4,7 +4,7 @@ import { EnvironmentEntity } from '@novu/dal'; import { UserSession } from '@novu/testing'; import { UserSessionData } from '@novu/shared'; -describe('Switch Environment - /auth/environments/:id/switch (POST)', async () => { +describe('Switch Environment - /auth/environments/:id/switch (POST) @skip-in-ee', async () => { let session: UserSession; describe('user has multiple environments', () => { diff --git a/apps/api/src/app/auth/e2e/switch-organization.e2e.ts b/apps/api/src/app/auth/e2e/switch-organization.e2e.ts index fe5e6251cc6..de4085464e4 100644 --- a/apps/api/src/app/auth/e2e/switch-organization.e2e.ts +++ b/apps/api/src/app/auth/e2e/switch-organization.e2e.ts @@ -4,7 +4,7 @@ import { OrganizationEntity } from '@novu/dal'; import { UserSession } from '@novu/testing'; import { MemberRoleEnum, UserSessionData } from '@novu/shared'; -describe('Switch Organization - /auth/organizations/:id/switch (POST)', async () => { +describe('Switch Organization - /auth/organizations/:id/switch (POST) @skip-in-ee', async () => { let session: UserSession; describe('no organization for user', () => { diff --git a/apps/api/src/app/auth/e2e/update-password.e2e.ts b/apps/api/src/app/auth/e2e/update-password.e2e.ts index 21e392522fa..834c16f548a 100644 --- a/apps/api/src/app/auth/e2e/update-password.e2e.ts +++ b/apps/api/src/app/auth/e2e/update-password.e2e.ts @@ -8,7 +8,7 @@ const PASSWORD_ERROR_MESSAGE = 'The new password must contain minimum 8 and maximum 64 characters,' + ' at least one uppercase letter, one lowercase letter, one number and one special character #?!@$%^&*()-'; -describe('User update password - /auth/update-password (POST)', async () => { +describe('User update password - /auth/update-password (POST) @skip-in-ee', async () => { let session: UserSession; before(async () => { diff --git a/apps/api/src/app/auth/e2e/user-registration.e2e.ts b/apps/api/src/app/auth/e2e/user-registration.e2e.ts index 9c3a31fc833..de8759361fb 100644 --- a/apps/api/src/app/auth/e2e/user-registration.e2e.ts +++ b/apps/api/src/app/auth/e2e/user-registration.e2e.ts @@ -1,13 +1,13 @@ -import { EnvironmentRepository, OrganizationRepository } from '@novu/dal'; +import { CommunityOrganizationRepository, EnvironmentRepository } from '@novu/dal'; import { UserSession } from '@novu/testing'; import jwt from 'jsonwebtoken'; import { expect } from 'chai'; import { MemberRoleEnum, UserSessionData } from '@novu/shared'; -describe('User registration - /auth/register (POST)', async () => { +describe('User registration - /auth/register (POST) @skip-in-ee', async () => { let session: UserSession; const environmentRepository = new EnvironmentRepository(); - const organizationRepository = new OrganizationRepository(); + const organizationRepository = new CommunityOrganizationRepository(); before(async () => { session = new UserSession(); diff --git a/apps/api/src/app/auth/ee.auth.module.config.ts b/apps/api/src/app/auth/ee.auth.module.config.ts new file mode 100644 index 00000000000..73ff2fb3b3e --- /dev/null +++ b/apps/api/src/app/auth/ee.auth.module.config.ts @@ -0,0 +1,58 @@ +import { + AuthService, + SwitchEnvironment, + SwitchOrganization, + injectRepositories, + PlatformException, +} from '@novu/application-generic'; +import { RolesGuard } from './framework/roles.guard'; +import { RootEnvironmentGuard } from './framework/root-environment-guard.service'; +import { MiddlewareConsumer, ModuleMetadata } from '@nestjs/common'; +import { ApiKeyStrategy } from './services/passport/apikey.strategy'; +import { JwtSubscriberStrategy } from './services/passport/subscriber-jwt.strategy'; +import { OrganizationModule } from '../organization/organization.module'; + +export function getEEModuleConfig(): ModuleMetadata { + const eeAuthPackage = require('@novu/ee-auth'); + const eeAuthModule = eeAuthPackage?.eEAuthModule; + + if (!eeAuthModule) { + throw new PlatformException('ee-auth module is not loaded'); + } + + return { + imports: [...eeAuthModule.imports, OrganizationModule], + controllers: [...eeAuthModule.controllers], + providers: [ + ...eeAuthModule.providers, + ...injectRepositories(), + // reused services + ApiKeyStrategy, + JwtSubscriberStrategy, + AuthService, + SwitchEnvironment, + SwitchOrganization, + RolesGuard, + RootEnvironmentGuard, + ], + exports: [ + ...eeAuthModule.exports, + RolesGuard, + RootEnvironmentGuard, + AuthService, + 'USER_REPOSITORY', + 'MEMBER_REPOSITORY', + 'ORGANIZATION_REPOSITORY', + ], + }; +} + +export function configure(consumer: MiddlewareConsumer) { + const eeAuthPackage = require('@novu/ee-auth'); + + if (!eeAuthPackage?.configure) { + throw new PlatformException('ee-auth configure() is not loaded'); + } + + eeAuthPackage.configure(consumer); +} diff --git a/apps/api/src/app/auth/framework/root-environment-guard.service.ts b/apps/api/src/app/auth/framework/root-environment-guard.service.ts index 3f285457bd6..942dfb0fd6c 100644 --- a/apps/api/src/app/auth/framework/root-environment-guard.service.ts +++ b/apps/api/src/app/auth/framework/root-environment-guard.service.ts @@ -1,13 +1,9 @@ import { CanActivate, ExecutionContext, forwardRef, Inject, Injectable, UnauthorizedException } from '@nestjs/common'; -import { Reflector } from '@nestjs/core'; import { AuthService } from '@novu/application-generic'; @Injectable() export class RootEnvironmentGuard implements CanActivate { - constructor( - private readonly reflector: Reflector, - @Inject(forwardRef(() => AuthService)) private authService: AuthService - ) {} + constructor(@Inject(forwardRef(() => AuthService)) private authService: AuthService) {} async canActivate(context: ExecutionContext) { const request = context.switchToHttp().getRequest(); diff --git a/apps/api/src/app/auth/legacy-ee-auth/auth.controller.ts b/apps/api/src/app/auth/legacy-ee-auth/auth.controller.ts new file mode 100644 index 00000000000..dc4d0ed14cf --- /dev/null +++ b/apps/api/src/app/auth/legacy-ee-auth/auth.controller.ts @@ -0,0 +1,42 @@ +import { + ClassSerializerInterceptor, + Controller, + Get, + Req, + Res, + UseGuards, + UseInterceptors, + Logger, +} from '@nestjs/common'; +import { AuthGuard } from '@nestjs/passport'; + +import { ApiException, buildOauthRedirectUrl } from '@novu/application-generic'; + +@Controller('/auth') +@UseInterceptors(ClassSerializerInterceptor) +export class AuthController { + @Get('/google') + googleAuth() { + Logger.verbose('Checking Google Auth'); + + if (!process.env.GOOGLE_OAUTH_CLIENT_ID || !process.env.GOOGLE_OAUTH_CLIENT_SECRET) { + throw new ApiException( + 'Google auth is not configured, please provide GOOGLE_OAUTH_CLIENT_ID and GOOGLE_OAUTH_CLIENT_SECRET as env variables' + ); + } + + Logger.verbose('Google Auth has all variables.'); + + return { + success: true, + }; + } + + @Get('/google/callback') + @UseGuards(AuthGuard('google')) + async googleCallback(@Req() request, @Res() response) { + const url = buildOauthRedirectUrl(request); + + return response.redirect(url); + } +} diff --git a/apps/api/src/app/auth/legacy-ee-auth/auth.module.ts b/apps/api/src/app/auth/legacy-ee-auth/auth.module.ts new file mode 100644 index 00000000000..c4d11c80bff --- /dev/null +++ b/apps/api/src/app/auth/legacy-ee-auth/auth.module.ts @@ -0,0 +1,76 @@ +import { MiddlewareConsumer, Module, NestModule, Provider, RequestMethod } from '@nestjs/common'; +import { JwtModule } from '@nestjs/jwt'; +import { PassportModule } from '@nestjs/passport'; +import passport from 'passport'; +import { AuthProviderEnum } from '@novu/shared'; +import { + AnalyticsService, + AuthService, + cacheService, + CreateUser, + SwitchEnvironment, + SwitchOrganization, +} from '@novu/application-generic'; +import { + EnvironmentRepository, + MemberRepository, + OrganizationRepository, + SubscriberRepository, + UserRepository, +} from '@novu/dal'; + +import { AuthController } from './auth.controller'; +import { GoogleStrategy } from './google.strategy'; + +const AUTH_STRATEGIES: Provider[] = []; +if (process.env.GOOGLE_OAUTH_CLIENT_ID) { + AUTH_STRATEGIES.push(GoogleStrategy); +} + +const DAL = [SubscriberRepository, OrganizationRepository, EnvironmentRepository, UserRepository]; +const SERVICES = [ + CreateUser, + AnalyticsService, + MemberRepository, + SwitchOrganization, + SwitchEnvironment, + cacheService, + AuthService, +]; +const PROVIDERS = [...DAL, ...SERVICES]; + +const PASSPORT_MODULE = PassportModule.register({ + defaultStrategy: AuthProviderEnum.GOOGLE, +}); + +@Module({ + imports: [ + PASSPORT_MODULE, + JwtModule.register({ + secretOrKeyProvider: () => process.env.JWT_SECRET as string, + signOptions: { + expiresIn: 360000, + }, + }), + ], + providers: [...AUTH_STRATEGIES, ...PROVIDERS], + controllers: [AuthController], + exports: [], +}) +export class LegacyEEAuthModule implements NestModule { + public configure(consumer: MiddlewareConsumer) { + if (process.env.GOOGLE_OAUTH_CLIENT_ID) { + consumer + .apply( + passport.authenticate(AuthProviderEnum.GOOGLE, { + session: false, + scope: ['profile', 'email'], + }) + ) + .forRoutes({ + path: '/auth/google', + method: RequestMethod.GET, + }); + } + } +} diff --git a/apps/api/src/app/auth/legacy-ee-auth/google.strategy.ts b/apps/api/src/app/auth/legacy-ee-auth/google.strategy.ts new file mode 100644 index 00000000000..92e9e52e1ee --- /dev/null +++ b/apps/api/src/app/auth/legacy-ee-auth/google.strategy.ts @@ -0,0 +1,59 @@ +import { Injectable } from '@nestjs/common'; +import { PassportStrategy } from '@nestjs/passport'; +import { OAuth2Strategy as Strategy } from 'passport-google-oauth'; +import { Metadata, StateStoreStoreCallback, StateStoreVerifyCallback } from 'passport-oauth2'; + +import { AuthProviderEnum } from '@novu/shared'; +import { AuthService } from '@novu/application-generic'; + +@Injectable() +export class GoogleStrategy extends PassportStrategy(Strategy, AuthProviderEnum.GOOGLE) { + constructor(private authService: AuthService) { + super({ + clientID: process.env.GOOGLE_OAUTH_CLIENT_ID, + clientSecret: process.env.GOOGLE_OAUTH_CLIENT_SECRET, + callbackURL: process.env.API_ROOT_URL + `/v1/auth/${AuthProviderEnum.GOOGLE}/callback`, + state: true, + passReqToCallback: true, + store: { + verify(req, state: string, meta: Metadata, callback: StateStoreVerifyCallback) { + callback(null, true, JSON.stringify(req.query)); + }, + store(req, meta: Metadata, callback: StateStoreStoreCallback) { + callback(null, JSON.stringify(req.query)); + }, + }, + }); + } + + async validate(req, accessToken: string, refreshToken: string, googleProfile, done: (err, data) => void) { + try { + const profile = { ...googleProfile._json, email: googleProfile.emails[0].value }; + const parsedState = this.parseState(req); + + const response = await this.authService.authenticate( + AuthProviderEnum.GOOGLE, + accessToken, + refreshToken, + profile, + parsedState?.distinctId, + parsedState?.source + ); + + done(null, { + token: response.token, + newUser: response.newUser, + }); + } catch (err) { + done(err, false); + } + } + + private parseState(req) { + try { + return JSON.parse(req.query.state); + } catch (e) { + return {}; + } + } +} diff --git a/apps/api/src/app/environments/e2e/regenerate-api-keys.e2e.ts b/apps/api/src/app/environments/e2e/regenerate-api-keys.e2e.ts index 135b372a644..aa5c1bacf57 100644 --- a/apps/api/src/app/environments/e2e/regenerate-api-keys.e2e.ts +++ b/apps/api/src/app/environments/e2e/regenerate-api-keys.e2e.ts @@ -2,7 +2,7 @@ import { UserSession } from '@novu/testing'; import { expect } from 'chai'; import { NOVU_ENCRYPTION_SUB_MASK } from '@novu/shared'; -describe('Environment - Regenerate Api Key', async () => { +describe('Environment - Regenerate Api Key @skip-in-ee', async () => { let session: UserSession; before(async () => { diff --git a/apps/api/src/app/environments/environments.controller.ts b/apps/api/src/app/environments/environments.controller.ts index 29d255ffb75..35130400135 100644 --- a/apps/api/src/app/environments/environments.controller.ts +++ b/apps/api/src/app/environments/environments.controller.ts @@ -84,7 +84,7 @@ export class EnvironmentsController { userId: user._id, organizationId: user.organizationId, // TODO: This is a temporary patch to include API keys when Novu API is accessed via a user JWT token - includeApiKeys: user?.iss === 'novu_api', + includeApiKeys: user?.iss === 'novu_api' || user?.iss === process.env.CLERK_ISSUER_URL, }) ); } diff --git a/apps/api/src/app/events/e2e/trigger-event.e2e.ts b/apps/api/src/app/events/e2e/trigger-event.e2e.ts index f3b89022647..1d6bae4486b 100644 --- a/apps/api/src/app/events/e2e/trigger-event.e2e.ts +++ b/apps/api/src/app/events/e2e/trigger-event.e2e.ts @@ -1297,7 +1297,7 @@ describe(`Trigger event - ${eventTriggerPath} (POST)`, function () { status: JobStatusEnum.COMPLETED, }); await promiseTimeout(100); - } while (completedCount !== 4); + } while (completedCount < 4); const jobs = await jobRepository.find({ _environmentId: session.environment._id, _templateId: template._id }); const statuses = jobs.map((job) => job.status).filter((value) => value !== JobStatusEnum.COMPLETED); diff --git a/apps/api/src/app/events/e2e/trigger-multicast.e2e.ts b/apps/api/src/app/events/e2e/trigger-multicast.e2e.ts index 11abe01be2d..95f5f0526f2 100644 --- a/apps/api/src/app/events/e2e/trigger-multicast.e2e.ts +++ b/apps/api/src/app/events/e2e/trigger-multicast.e2e.ts @@ -81,6 +81,19 @@ function expectBulkSingleSubscriberStub( } } +function getEchoGatewayModule() { + if (process.env.NOVU_ENTERPRISE === 'true' || process.env.CI_EE_TEST === 'true') { + const eeEchoBridgeWorker = require('@novu/ee-bridge-worker'); + if (!eeEchoBridgeWorker.BridgeGatewayModule) { + throw new Error("BridgeGatewayModule doesn't exist"); + } + + return [eeEchoBridgeWorker.BridgeGatewayModule]; + } + + return []; +} + describe('TriggerMulticast', () => { let triggerMulticast: TriggerMulticast; let subscriberProcessQueueService: SubscriberProcessQueueService; @@ -88,7 +101,7 @@ describe('TriggerMulticast', () => { beforeEach(async () => { const moduleRef = await Test.createTestingModule({ - imports: [SharedModule, EventsModule], + imports: [SharedModule, EventsModule, ...getEchoGatewayModule()], providers: [ TriggerMulticast, { diff --git a/apps/api/src/app/events/usecases/parse-event-request/parse-event-request.e2e.ts b/apps/api/src/app/events/usecases/parse-event-request/parse-event-request.e2e.ts index 2dfcc1705bb..969177ccaff 100644 --- a/apps/api/src/app/events/usecases/parse-event-request/parse-event-request.e2e.ts +++ b/apps/api/src/app/events/usecases/parse-event-request/parse-event-request.e2e.ts @@ -11,6 +11,19 @@ import { EventsModule } from '../../events.module'; import { ParseEventRequestCommand, ParseEventRequestMulticastCommand } from './parse-event-request.command'; import { ParseEventRequest } from './parse-event-request.usecase'; +function getEchoGatewayModule() { + if (process.env.NOVU_ENTERPRISE === 'true' || process.env.CI_EE_TEST === 'true') { + const eeEchoBridgeWorker = require('@novu/ee-bridge-worker'); + if (!eeEchoBridgeWorker.BridgeGatewayModule) { + throw new Error("BridgeGatewayModule doesn't exist"); + } + + return [eeEchoBridgeWorker.BridgeGatewayModule]; + } + + return []; +} + describe('ParseEventRequest Usecase', () => { let session: UserSession; let subscribersService: SubscribersService; @@ -19,7 +32,7 @@ describe('ParseEventRequest Usecase', () => { beforeEach(async () => { const moduleRef = await Test.createTestingModule({ - imports: [SharedModule, EventsModule], + imports: [SharedModule, EventsModule, ...getEchoGatewayModule()], providers: [], }).compile(); diff --git a/apps/api/src/app/events/usecases/parse-event-request/parse-event-request.usecase.ts b/apps/api/src/app/events/usecases/parse-event-request/parse-event-request.usecase.ts index 32ef239dc45..f27c5b8ed29 100644 --- a/apps/api/src/app/events/usecases/parse-event-request/parse-event-request.usecase.ts +++ b/apps/api/src/app/events/usecases/parse-event-request/parse-event-request.usecase.ts @@ -352,9 +352,7 @@ export class ParseEventRequest { }); // check if user is using personal email - const user = await this.userRepository.findOne({ - _id: command.userId, - }); + const user = await this.userRepository.findById(command.userId); if (!user) throw new ApiException('User not found'); diff --git a/apps/api/src/app/invites/e2e/accept-invite.e2e.ts b/apps/api/src/app/invites/e2e/accept-invite.e2e.ts index 0ae6878ba40..2b6d81dd59e 100644 --- a/apps/api/src/app/invites/e2e/accept-invite.e2e.ts +++ b/apps/api/src/app/invites/e2e/accept-invite.e2e.ts @@ -1,12 +1,12 @@ -import { MemberRepository, MemberEntity } from '@novu/dal'; +import { MemberEntity, CommunityMemberRepository } from '@novu/dal'; import { UserSession } from '@novu/testing'; import { MemberStatusEnum } from '@novu/shared'; import { expect } from 'chai'; -describe('Accept invite - /invites/:inviteToken/accept (POST)', async () => { +describe('Accept invite - /invites/:inviteToken/accept (POST) @skip-in-ee', async () => { let session: UserSession; let invitedUserSession: UserSession; - const memberRepository = new MemberRepository(); + const memberRepository = new CommunityMemberRepository(); async function setup() { session = new UserSession(); diff --git a/apps/api/src/app/invites/e2e/bulk-invite.e2e.ts b/apps/api/src/app/invites/e2e/bulk-invite.e2e.ts index a8a639ac4ca..1d142a97e85 100644 --- a/apps/api/src/app/invites/e2e/bulk-invite.e2e.ts +++ b/apps/api/src/app/invites/e2e/bulk-invite.e2e.ts @@ -1,12 +1,11 @@ -import { OrganizationRepository, MemberRepository } from '@novu/dal'; +import { CommunityMemberRepository } from '@novu/dal'; import { UserSession } from '@novu/testing'; import { IBulkInviteResponse, MemberRoleEnum, MemberStatusEnum } from '@novu/shared'; import { expect } from 'chai'; -describe('Bulk invite members - /invites/bulk (POST)', async () => { +describe('Bulk invite members - /invites/bulk (POST) @skip-in-ee', async () => { let session: UserSession; - const organizationRepository = new OrganizationRepository(); - const memberRepository = new MemberRepository(); + const memberRepository = new CommunityMemberRepository(); before(async () => { session = new UserSession(); diff --git a/apps/api/src/app/invites/e2e/get-invite.e2e.ts b/apps/api/src/app/invites/e2e/get-invite.e2e.ts index f53d0a70290..7e4213f3cb1 100644 --- a/apps/api/src/app/invites/e2e/get-invite.e2e.ts +++ b/apps/api/src/app/invites/e2e/get-invite.e2e.ts @@ -1,12 +1,12 @@ -import { OrganizationRepository, MemberRepository } from '@novu/dal'; +import { CommunityOrganizationRepository, CommunityMemberRepository } from '@novu/dal'; import { UserSession } from '@novu/testing'; import { MemberStatusEnum } from '@novu/shared'; import { expect } from 'chai'; -describe('Get invite object - /invites/:inviteToken (GET)', async () => { +describe('Get invite object - /invites/:inviteToken (GET) @skip-in-ee', async () => { let session: UserSession; - const organizationRepository = new OrganizationRepository(); - const memberRepository = new MemberRepository(); + const organizationRepository = new CommunityOrganizationRepository(); + const memberRepository = new CommunityMemberRepository(); describe('valid token returned', async () => { before(async () => { diff --git a/apps/api/src/app/invites/e2e/resend-invite.e2e.ts b/apps/api/src/app/invites/e2e/resend-invite.e2e.ts index 66dd6f75484..5bfeeea96bc 100644 --- a/apps/api/src/app/invites/e2e/resend-invite.e2e.ts +++ b/apps/api/src/app/invites/e2e/resend-invite.e2e.ts @@ -1,12 +1,12 @@ -import { MemberRepository, MemberEntity } from '@novu/dal'; +import { MemberEntity, CommunityMemberRepository } from '@novu/dal'; import { UserSession } from '@novu/testing'; import { MemberStatusEnum } from '@novu/shared'; import { expect } from 'chai'; -describe('Resend invite - /invites/resend (POST)', async () => { +describe('Resend invite - /invites/resend (POST) @skip-in-ee', async () => { let session: UserSession; let invitee: MemberEntity; - const memberRepository = new MemberRepository(); + const memberRepository = new CommunityMemberRepository(); async function setup() { session = new UserSession(); diff --git a/apps/api/src/app/organization/e2e/create-organization.e2e.ts b/apps/api/src/app/organization/e2e/create-organization.e2e.ts index fb771d75a2c..82fba343a45 100644 --- a/apps/api/src/app/organization/e2e/create-organization.e2e.ts +++ b/apps/api/src/app/organization/e2e/create-organization.e2e.ts @@ -1,11 +1,11 @@ import { expect } from 'chai'; import { - MemberRepository, - OrganizationRepository, - UserRepository, IntegrationRepository, EnvironmentRepository, + CommunityOrganizationRepository, + CommunityUserRepository, + CommunityMemberRepository, } from '@novu/dal'; import { UserSession } from '@novu/testing'; import { @@ -18,11 +18,11 @@ import { SmsProviderIdEnum, } from '@novu/shared'; -describe('Create Organization - /organizations (POST)', async () => { +describe('Create Organization - /organizations (POST) @skip-in-ee', async () => { let session: UserSession; - const organizationRepository = new OrganizationRepository(); - const userRepository = new UserRepository(); - const memberRepository = new MemberRepository(); + const organizationRepository = new CommunityOrganizationRepository(); + const userRepository = new CommunityUserRepository(); + const memberRepository = new CommunityMemberRepository(); const integrationRepository = new IntegrationRepository(); const environmentRepository = new EnvironmentRepository(); diff --git a/apps/api/src/app/organization/e2e/get-members.e2e.ts b/apps/api/src/app/organization/e2e/get-members.e2e.ts index f34537a28a6..baba9af11b4 100644 --- a/apps/api/src/app/organization/e2e/get-members.e2e.ts +++ b/apps/api/src/app/organization/e2e/get-members.e2e.ts @@ -1,13 +1,13 @@ -import { MemberRepository } from '@novu/dal'; +import { CommunityMemberRepository } from '@novu/dal'; import { UserSession } from '@novu/testing'; import { expect } from 'chai'; import { MemberRoleEnum } from '@novu/shared'; -describe('Get members - /organization/members (GET)', async () => { +describe('Get members - /organization/members (GET) @skip-in-ee', async () => { let session: UserSession; let otherSession: UserSession; - const memberRepository = new MemberRepository(); + const memberRepository = new CommunityMemberRepository(); before(async () => { session = new UserSession(); diff --git a/apps/api/src/app/organization/e2e/get-organizations.e2e.ts b/apps/api/src/app/organization/e2e/get-organizations.e2e.ts index 72ef2502246..741334e3b37 100644 --- a/apps/api/src/app/organization/e2e/get-organizations.e2e.ts +++ b/apps/api/src/app/organization/e2e/get-organizations.e2e.ts @@ -1,16 +1,16 @@ -import { MemberRepository, OrganizationEntity } from '@novu/dal'; +import { CommunityMemberRepository, OrganizationEntity } from '@novu/dal'; import { UserSession } from '@novu/testing'; import { expect } from 'chai'; import { MemberRoleEnum } from '@novu/shared'; -describe('Get organizations - /organizations (GET)', async () => { +describe('Get organizations - /organizations (GET) @skip-in-ee', async () => { let session: UserSession; let otherSession: UserSession; let thirdSession: UserSession; let thirdOldOrganization: OrganizationEntity; - const memberRepository = new MemberRepository(); + const memberRepository = new CommunityMemberRepository(); before(async () => { session = new UserSession(); diff --git a/apps/api/src/app/organization/e2e/members/change-member-role.e2e.ts b/apps/api/src/app/organization/e2e/members/change-member-role.e2e.ts index f7d4a670730..2cfc32e6bbe 100644 --- a/apps/api/src/app/organization/e2e/members/change-member-role.e2e.ts +++ b/apps/api/src/app/organization/e2e/members/change-member-role.e2e.ts @@ -1,12 +1,11 @@ -import { OrganizationRepository, MemberRepository } from '@novu/dal'; +import { CommunityMemberRepository } from '@novu/dal'; import { UserSession } from '@novu/testing'; import { MemberRoleEnum, MemberStatusEnum } from '@novu/shared'; import { expect } from 'chai'; import { describe } from 'mocha'; -describe('Change member role - /organizations/members/:memberId/role (PUT)', async () => { - const organizationRepository = new OrganizationRepository(); - const memberRepository = new MemberRepository(); +describe('Change member role - /organizations/members/:memberId/role (PUT) @skip-in-ee', async () => { + const memberRepository = new CommunityMemberRepository(); let session: UserSession; let user2: UserSession; let user3: UserSession; diff --git a/apps/api/src/app/organization/e2e/members/get-members.e2e.ts b/apps/api/src/app/organization/e2e/members/get-members.e2e.ts index b2d6fc350e8..114467aadf7 100644 --- a/apps/api/src/app/organization/e2e/members/get-members.e2e.ts +++ b/apps/api/src/app/organization/e2e/members/get-members.e2e.ts @@ -1,13 +1,12 @@ -import { MemberEntity, OrganizationRepository, MemberRepository } from '@novu/dal'; +import { MemberEntity, MemberRepository, CommunityMemberRepository } from '@novu/dal'; import { UserSession } from '@novu/testing'; import { MemberRoleEnum, MemberStatusEnum } from '@novu/shared'; import { expect } from 'chai'; import { describe } from 'mocha'; -describe('Get Organization members - /organizations/members (GET)', async () => { +describe('Get Organization members - /organizations/members (GET) @skip-in-ee', async () => { let session: UserSession; - const organizationRepository = new OrganizationRepository(); - const memberRepository = new MemberRepository(); + const memberRepository = new CommunityMemberRepository(); let user2: UserSession; let user3: UserSession; diff --git a/apps/api/src/app/organization/e2e/members/remove-member.e2e.ts b/apps/api/src/app/organization/e2e/members/remove-member.e2e.ts index 41163a189fd..ad31f8f82ec 100644 --- a/apps/api/src/app/organization/e2e/members/remove-member.e2e.ts +++ b/apps/api/src/app/organization/e2e/members/remove-member.e2e.ts @@ -1,13 +1,13 @@ -import { MemberEntity, OrganizationRepository, MemberRepository, EnvironmentRepository } from '@novu/dal'; +import { MemberEntity, EnvironmentRepository, CommunityMemberRepository } from '@novu/dal'; import { UserSession } from '@novu/testing'; import { MemberRoleEnum, MemberStatusEnum } from '@novu/shared'; import { expect } from 'chai'; import { describe } from 'mocha'; -describe('Remove organization member - /organizations/members/:memberId (DELETE)', async () => { +describe('Remove organization member - /organizations/members/:memberId (DELETE) @skip-in-ee', async () => { let session: UserSession; - const memberRepository = new MemberRepository(); + const memberRepository = new CommunityMemberRepository(); const environmentRepository = new EnvironmentRepository(); let user2: UserSession; let user3: UserSession; diff --git a/apps/api/src/app/organization/e2e/rename-organization.e2e.ts b/apps/api/src/app/organization/e2e/rename-organization.e2e.ts index cf7ea613b70..b9b575072ca 100644 --- a/apps/api/src/app/organization/e2e/rename-organization.e2e.ts +++ b/apps/api/src/app/organization/e2e/rename-organization.e2e.ts @@ -1,10 +1,8 @@ -import { OrganizationRepository } from '@novu/dal'; import { UserSession } from '@novu/testing'; import { expect } from 'chai'; describe('Rename Organization - /organizations (PATCH)', function () { let session: UserSession; - const organizationRepository = new OrganizationRepository(); beforeEach(async () => { session = new UserSession(); @@ -18,7 +16,8 @@ describe('Rename Organization - /organizations (PATCH)', function () { await session.testAgent.patch('/v1/organizations').send(payload); - const organization = await organizationRepository.findById(session.organization._id); + const { body } = await session.testAgent.get('/v1/organizations/me').expect(200); + const organization = body.data; expect(organization?.name).to.equal(payload.name); }); diff --git a/apps/api/src/app/organization/e2e/set-default-locale.e2e-ee.ts b/apps/api/src/app/organization/e2e/set-default-locale.e2e-ee.ts deleted file mode 100644 index 42443f08660..00000000000 --- a/apps/api/src/app/organization/e2e/set-default-locale.e2e-ee.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { OrganizationRepository } from '@novu/dal'; -import { UserSession } from '@novu/testing'; -import { expect } from 'chai'; - -describe('Set default locale for organization - /organizations (POST)', async () => { - let session: UserSession; - const organizationRepository = new OrganizationRepository(); - - before(async () => { - session = new UserSession(); - await session.initialize(); - }); - - it('should set default locale for organization', async () => { - let org = await organizationRepository.findById(session.organization._id); - expect(org?.defaultLocale).to.be.equal(undefined); - - let result = await session.testAgent.put(`/v1/organizations/language`).send({ - locale: 'en_US', - }); - expect(result.body.data.defaultLocale).to.eq('en_US'); - org = await organizationRepository.findById(session.organization._id); - expect(org?.defaultLocale).to.be.equal('en_US'); - - result = await session.testAgent.put(`/v1/organizations/language`).send({ - locale: 'en_GB', - }); - expect(result.body.data.defaultLocale).to.eq('en_GB'); - org = await organizationRepository.findById(session.organization._id); - expect(org?.defaultLocale).to.be.equal('en_GB'); - }); -}); diff --git a/apps/api/src/app/organization/e2e/sync-organization.e2e-ee.ts b/apps/api/src/app/organization/e2e/sync-organization.e2e-ee.ts new file mode 100644 index 00000000000..3081ce3783c --- /dev/null +++ b/apps/api/src/app/organization/e2e/sync-organization.e2e-ee.ts @@ -0,0 +1,182 @@ +import { expect } from 'chai'; +import { UserSession } from '@novu/testing'; +import { ClerkClientMock } from '@novu/ee-auth'; +import { + ApiServiceLevelEnum, + EmailProviderIdEnum, + JobTitleEnum, + Organization, + SmsProviderIdEnum, + UpdateExternalOrganizationDto, + User, +} from '@novu/shared'; +import { EnvironmentRepository, IntegrationRepository, OrganizationEntity } from '@novu/dal'; + +// TODO: rework to clerk webhook +describe.skip('Sync Organization - /organizations (POST)', async () => { + let session: UserSession; + let clerkClientMock: ClerkClientMock; + let clerkUser: User; + let clerkOrganization: Organization; + let internalOrganization: OrganizationEntity; + + const integrationRepository = new IntegrationRepository(); + const environmentRepository = new EnvironmentRepository(); + + const testOrganization: UpdateExternalOrganizationDto = { + jobTitle: JobTitleEnum.ENGINEER, + domain: 'example.com', + productUseCases: { + in_app: true, + delay: true, + }, + }; + + function getRequest(payload: UpdateExternalOrganizationDto, origin: string = process.env.FRONT_BASE_URL) { + return session.testAgent.post('/v1/organizations/').set('origin', origin).send(payload); + } + + before(async () => { + session = new UserSession(); + clerkClientMock = new ClerkClientMock(); + + // must be an existing Clerk user in an existing Clerk organization + clerkUser = await clerkClientMock.users.getUser('clerk_user_1'); + clerkOrganization = await clerkClientMock.organizations.getOrganization({ organizationId: 'clerk_org_1' }); + + await session.updateEETokenClaims({ + _id: clerkUser.id, + org_id: clerkOrganization.id, + externalId: clerkUser.externalId!, // null before syncing + externalOrgId: clerkOrganization.publicMetadata.externalOrgId, // null before syncing + }); + + // sync the user first since the organization is dependent on the existing synced userId + await session.testAgent.post('/v1/users').set('origin', process.env.FRONT_BASE_URL).expect(201); + + // TODO: ee-billing is not mocked and throws an error here + const { body } = await getRequest(testOrganization).expect(201); + internalOrganization = body.data; + }); + + it('should throw an error when internal organization already exists for Clerk organization', async () => { + const { body } = await getRequest(testOrganization).expect(400); + + expect(body.message).to.equal(`Internal organization with externalId: ${clerkOrganization.id} already exists`); + }); + + it('should throw an error when Clerk organization does not exist', async () => { + const id = 'not_existing_org_id'; + await session.updateEETokenClaims({ + _id: clerkUser.id, + org_id: id, + externalId: clerkUser.externalId!, + externalOrgId: undefined, + }); + + const { body } = await getRequest(testOrganization).expect(400); + + expect(body.message).to.equal(`Clerk organization with id: ${id} does not exist`); + }); + + it('should not allow API call from different origin than Novu frontend', async () => { + const origin = 'https://external.com'; + const { body } = await getRequest(testOrganization, origin).expect(403); + + expect(body.message).to.equal('Forbidden'); + }); + + it('should create internal organization with externalId of given existing Clerk organization and metadata', async () => { + const updatedClerkOrganization: Organization = await clerkClientMock.organizations.getOrganization({ + organizationId: clerkOrganization.id, + }); + + expect(internalOrganization._id).to.equal(updatedClerkOrganization.publicMetadata.externalOrgId); + expect(internalOrganization.externalId).to.equal(updatedClerkOrganization.id); + + // these are stored in the Clerk organization only and then concatenated with the response + expect(internalOrganization.name).to.equal(updatedClerkOrganization.name); + expect(internalOrganization.logo).to.equal(updatedClerkOrganization.imageUrl); + }); + + it('should have all internal attributes set correctly', async () => { + expect(internalOrganization.domain).to.equal(testOrganization.domain); + expect(internalOrganization.productUseCases?.in_app).to.eq(testOrganization.productUseCases?.in_app); + expect(internalOrganization.productUseCases?.delay).to.eq(testOrganization.productUseCases?.delay); + expect(internalOrganization.apiServiceLevel).to.eq(ApiServiceLevelEnum.FREE); + }); + + it('should update user job title on organization creation', async () => { + clerkUser = await clerkClientMock.users.getUser('clerk_user_1'); + + expect(clerkUser.publicMetadata.jobTitle).to.eq(testOrganization.jobTitle); + }); + + it('should create organization with built in Novu integrations and set them as primary', async () => { + const integrations = await integrationRepository.find({ _organizationId: internalOrganization._id }); + const environments = await environmentRepository.find({ _organizationId: internalOrganization._id }); + const productionEnv = environments.find((e) => e.name === 'Production'); + const developmentEnv = environments.find((e) => e.name === 'Development'); + const novuEmailIntegration = integrations.filter( + (i) => i.active && i.name === 'Novu Email' && i.providerId === EmailProviderIdEnum.Novu + ); + const novuSmsIntegration = integrations.filter( + (i) => i.active && i.name === 'Novu SMS' && i.providerId === SmsProviderIdEnum.Novu + ); + const novuEmailIntegrationProduction = novuEmailIntegration.filter( + (el) => el._environmentId === productionEnv?._id + ); + const novuEmailIntegrationDevelopment = novuEmailIntegration.filter( + (el) => el._environmentId === developmentEnv?._id + ); + const novuSmsIntegrationProduction = novuSmsIntegration.filter((el) => el._environmentId === productionEnv?._id); + const novuSmsIntegrationDevelopment = novuSmsIntegration.filter((el) => el._environmentId === developmentEnv?._id); + + expect(integrations.length).to.eq(4); + expect(novuEmailIntegration?.length).to.eq(2); + expect(novuSmsIntegration?.length).to.eq(2); + + expect(novuEmailIntegrationProduction.length).to.eq(1); + expect(novuSmsIntegrationProduction.length).to.eq(1); + expect(novuEmailIntegrationDevelopment.length).to.eq(1); + expect(novuSmsIntegrationDevelopment.length).to.eq(1); + + expect(novuEmailIntegrationProduction[0].primary).to.eq(true); + expect(novuSmsIntegrationProduction[0].primary).to.eq(true); + expect(novuEmailIntegrationDevelopment[0].primary).to.eq(true); + expect(novuSmsIntegrationDevelopment[0].primary).to.eq(true); + }); + + it('when Novu SMS credentials are not set it should not create Novu SMS integration', async () => { + const oldNovuSmsIntegrationAccountSid = process.env.NOVU_SMS_INTEGRATION_ACCOUNT_SID; + process.env.NOVU_SMS_INTEGRATION_ACCOUNT_SID = ''; + + // same user creating new org + await session.updateEETokenClaims({ + _id: clerkUser.id, + org_id: 'clerk_org_2', + externalId: clerkUser.externalId!, + externalOrgId: undefined, + }); + + const { body } = await getRequest({ + domain: 'example2.com', + }).expect(201); + + internalOrganization = body.data; + + const integrations = await integrationRepository.find({ _organizationId: internalOrganization._id }); + const environments = await environmentRepository.find({ _organizationId: internalOrganization._id }); + const productionEnv = environments.find((e) => e.name === 'Production'); + const developmentEnv = environments.find((e) => e.name === 'Development'); + const novuEmailIntegrations = integrations.filter( + (i) => i.active && i.name === 'Novu Email' && i.providerId === EmailProviderIdEnum.Novu + ); + + expect(integrations.length).to.eq(2); + expect(novuEmailIntegrations?.length).to.eq(2); + expect(novuEmailIntegrations.filter((el) => el._environmentId === productionEnv?._id).length).to.eq(1); + expect(novuEmailIntegrations.filter((el) => el._environmentId === developmentEnv?._id).length).to.eq(1); + process.env.NOVU_SMS_INTEGRATION_ACCOUNT_SID = oldNovuSmsIntegrationAccountSid; + }); +}); diff --git a/apps/api/src/app/organization/e2e/update-branding-details.e2e.ts b/apps/api/src/app/organization/e2e/update-branding-details.e2e.ts index ee051c6b963..da8c46fb951 100644 --- a/apps/api/src/app/organization/e2e/update-branding-details.e2e.ts +++ b/apps/api/src/app/organization/e2e/update-branding-details.e2e.ts @@ -1,10 +1,8 @@ -import { OrganizationRepository } from '@novu/dal'; import { processTestAgentExpectedStatusCode, UserSession } from '@novu/testing'; import { expect } from 'chai'; describe('Update Branding Details - /organizations/branding (PUT)', function () { let session: UserSession; - const organizationRepository = new OrganizationRepository(); beforeEach(async () => { session = new UserSession(); @@ -17,8 +15,9 @@ describe('Update Branding Details - /organizations/branding (PUT)', function () }; await session.testAgent.patch('/v1/organizations').send(payload).expect(processTestAgentExpectedStatusCode(200)); + const { body } = await session.testAgent.get('/v1/organizations/me').expect(200); + const organization = body.data; - const organization = await organizationRepository.findById(session.organization._id); expect(organization?.name).to.equal(payload.name); expect(organization?.logo).to.equal(session.organization.logo); }); @@ -37,7 +36,8 @@ describe('Update Branding Details - /organizations/branding (PUT)', function () .send(payload) .expect(processTestAgentExpectedStatusCode(200)); - const organization = await organizationRepository.findById(session.organization._id); + const { body } = await session.testAgent.get('/v1/organizations/me').expect(200); + const organization = body.data; expect(organization?.branding.color).to.equal(payload.color); expect(organization?.branding.logo).to.equal(payload.logo); diff --git a/apps/api/src/app/organization/ee.organization.controller.ts b/apps/api/src/app/organization/ee.organization.controller.ts new file mode 100644 index 00000000000..d95738ae8a1 --- /dev/null +++ b/apps/api/src/app/organization/ee.organization.controller.ts @@ -0,0 +1,92 @@ +import { + Body, + ClassSerializerInterceptor, + Controller, + Get, + Patch, + Put, + UseGuards, + UseInterceptors, +} from '@nestjs/common'; +import { UserSessionData, MemberRoleEnum } from '@novu/shared'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; +import { Roles } from '../auth/framework/roles.decorator'; +import { UserSession } from '../shared/framework/user.decorator'; +import { UserAuthGuard } from '../auth/framework/user.auth.guard'; +import { UpdateBrandingDetailsCommand } from './usecases/update-branding-details/update-branding-details.command'; +import { UpdateBrandingDetails } from './usecases/update-branding-details/update-branding-details.usecase'; +import { GetMyOrganization } from './usecases/get-my-organization/get-my-organization.usecase'; +import { GetMyOrganizationCommand } from './usecases/get-my-organization/get-my-organization.command'; +import { IGetMyOrganizationDto } from './dtos/get-my-organization.dto'; +import { RenameOrganizationCommand } from './usecases/rename-organization/rename-organization-command'; +import { RenameOrganization } from './usecases/rename-organization/rename-organization.usecase'; +import { RenameOrganizationDto } from './dtos/rename-organization.dto'; +import { UpdateBrandingDetailsDto } from './dtos/update-branding-details.dto'; +import { ExternalApiAccessible } from '../auth/framework/external-api.decorator'; +import { ApiCommonResponses, ApiResponse } from '../shared/framework/response.decorator'; +import { OrganizationBrandingResponseDto, OrganizationResponseDto } from './dtos/organization-response.dto'; + +@Controller('/organizations') +@UseInterceptors(ClassSerializerInterceptor) +@UseGuards(UserAuthGuard) +@ApiTags('Organizations') +@ApiCommonResponses() +export class EEOrganizationController { + constructor( + private updateBrandingDetailsUsecase: UpdateBrandingDetails, + private getMyOrganizationUsecase: GetMyOrganization, + private renameOrganizationUsecase: RenameOrganization + ) {} + + @Get('/me') + @ExternalApiAccessible() + @ApiResponse(OrganizationResponseDto) + @ApiOperation({ + summary: 'Fetch current organization details', + }) + async getMyOrganization(@UserSession() user: UserSessionData): Promise { + const command = GetMyOrganizationCommand.create({ + userId: user._id, + id: user.organizationId, + }); + + return await this.getMyOrganizationUsecase.execute(command); + } + + @Put('/branding') + @ExternalApiAccessible() + @ApiResponse(OrganizationBrandingResponseDto) + @ApiOperation({ + summary: 'Update organization branding details', + }) + async updateBrandingDetails(@UserSession() user: UserSessionData, @Body() body: UpdateBrandingDetailsDto) { + return await this.updateBrandingDetailsUsecase.execute( + UpdateBrandingDetailsCommand.create({ + logo: body.logo, + color: body.color, + userId: user._id, + id: user.organizationId, + fontColor: body.fontColor, + fontFamily: body.fontFamily, + contentBackground: body.contentBackground, + }) + ); + } + + @Patch('/') + @ExternalApiAccessible() + @Roles(MemberRoleEnum.ADMIN) + @ApiResponse(RenameOrganizationDto) + @ApiOperation({ + summary: 'Rename organization name', + }) + async renameOrganization(@UserSession() user: UserSessionData, @Body() body: RenameOrganizationDto) { + return await this.renameOrganizationUsecase.execute( + RenameOrganizationCommand.create({ + name: body.name, + userId: user._id, + id: user.organizationId, + }) + ); + } +} diff --git a/apps/api/src/app/organization/organization.module.ts b/apps/api/src/app/organization/organization.module.ts index b9764c53d60..f1c356a5113 100644 --- a/apps/api/src/app/organization/organization.module.ts +++ b/apps/api/src/app/organization/organization.module.ts @@ -17,6 +17,8 @@ import { OrganizationController } from './organization.controller'; import { USE_CASES } from './usecases'; import { AuthModule } from '../auth/auth.module'; import { Type } from '@nestjs/common/interfaces/type.interface'; +import { EEOrganizationController } from './ee.organization.controller'; +import { isClerkEnabled } from '@novu/shared'; const enterpriseImports = (): Array | ForwardReference> => { const modules: Array | ForwardReference> = []; @@ -33,6 +35,14 @@ const enterpriseImports = (): Array AuthModule), ...enterpriseImports(), ], - controllers: [OrganizationController], + controllers: [...getControllers()], providers: [...USE_CASES], exports: [...USE_CASES], }) export class OrganizationModule implements NestModule { configure(consumer: MiddlewareConsumer): MiddlewareConsumer | void { - consumer.apply(AuthGuard).exclude({ - method: RequestMethod.GET, - path: '/organizations/invite/:inviteToken', - }); + if (process.env.NOVU_ENTERPRISE !== 'true' && process.env.CI_EE_TEST !== 'true') { + consumer.apply(AuthGuard).exclude({ + method: RequestMethod.GET, + path: '/organizations/invite/:inviteToken', + }); + } } } diff --git a/apps/api/src/app/organization/usecases/create-organization/sync-external-organization/sync-external-organization.command.ts b/apps/api/src/app/organization/usecases/create-organization/sync-external-organization/sync-external-organization.command.ts new file mode 100644 index 00000000000..43f793fa345 --- /dev/null +++ b/apps/api/src/app/organization/usecases/create-organization/sync-external-organization/sync-external-organization.command.ts @@ -0,0 +1,8 @@ +import { IsString, IsDefined, IsEnum, IsOptional } from 'class-validator'; +import { AuthenticatedCommand } from '@novu/application-generic'; + +export class SyncExternalOrganizationCommand extends AuthenticatedCommand { + @IsDefined() + @IsString() + externalId: string; +} diff --git a/apps/api/src/app/organization/usecases/create-organization/sync-external-organization/sync-external-organization.usecase.ts b/apps/api/src/app/organization/usecases/create-organization/sync-external-organization/sync-external-organization.usecase.ts new file mode 100644 index 00000000000..c3844045c6f --- /dev/null +++ b/apps/api/src/app/organization/usecases/create-organization/sync-external-organization/sync-external-organization.usecase.ts @@ -0,0 +1,110 @@ +import { BadRequestException, Injectable, Logger, Scope } from '@nestjs/common'; +import { OrganizationEntity, OrganizationRepository, UserRepository } from '@novu/dal'; +import { AnalyticsService } from '@novu/application-generic'; + +import { CreateEnvironmentCommand } from '../../../../environments/usecases/create-environment/create-environment.command'; +import { CreateEnvironment } from '../../../../environments/usecases/create-environment/create-environment.usecase'; +import { GetOrganizationCommand } from '../../get-organization/get-organization.command'; +import { GetOrganization } from '../../get-organization/get-organization.usecase'; + +import { ApiException } from '../../../../shared/exceptions/api.exception'; +import { CreateNovuIntegrations } from '../../../../integrations/usecases/create-novu-integrations/create-novu-integrations.usecase'; +import { CreateNovuIntegrationsCommand } from '../../../../integrations/usecases/create-novu-integrations/create-novu-integrations.command'; +import { ModuleRef } from '@nestjs/core'; +import { SyncExternalOrganizationCommand } from './sync-external-organization.command'; + +// TODO: eventually move to @novu/ee-auth +@Injectable({ + scope: Scope.REQUEST, +}) +export class SyncExternalOrganization { + constructor( + private readonly organizationRepository: OrganizationRepository, + private readonly getOrganizationUsecase: GetOrganization, + private readonly userRepository: UserRepository, + private readonly createEnvironmentUsecase: CreateEnvironment, + private readonly createNovuIntegrations: CreateNovuIntegrations, + private analyticsService: AnalyticsService, + private moduleRef: ModuleRef + ) {} + + async execute(command: SyncExternalOrganizationCommand): Promise { + const user = await this.userRepository.findById(command.userId); + if (!user) throw new ApiException('User not found'); + + const organization = await this.organizationRepository.create({ + externalId: command.externalId, + }); + + const devEnv = await this.createEnvironmentUsecase.execute( + CreateEnvironmentCommand.create({ + userId: user._id, + name: 'Development', + organizationId: organization._id, + }) + ); + + await this.createNovuIntegrations.execute( + CreateNovuIntegrationsCommand.create({ + environmentId: devEnv._id, + organizationId: devEnv._organizationId, + userId: user._id, + }) + ); + + const prodEnv = await this.createEnvironmentUsecase.execute( + CreateEnvironmentCommand.create({ + userId: user._id, + name: 'Production', + organizationId: organization._id, + parentEnvironmentId: devEnv._id, + }) + ); + + await this.createNovuIntegrations.execute( + CreateNovuIntegrationsCommand.create({ + environmentId: prodEnv._id, + organizationId: prodEnv._organizationId, + userId: user._id, + }) + ); + + this.analyticsService.upsertGroup(organization._id, organization, user); + + this.analyticsService.track('[Authentication] - Create Organization', user._id, { + _organization: organization._id, + }); + + const organizationAfterChanges = await this.getOrganizationUsecase.execute( + GetOrganizationCommand.create({ + id: organization._id, + userId: command.userId, + }) + ); + + if (organizationAfterChanges !== null) { + await this.startFreeTrial(user._id, organizationAfterChanges._id); + } + + return organizationAfterChanges as OrganizationEntity; + } + + private async startFreeTrial(userId: string, organizationId: string) { + try { + if (process.env.NOVU_ENTERPRISE === 'true' || process.env.CI_EE_TEST === 'true') { + if (!require('@novu/ee-billing')?.StartReverseFreeTrial) { + throw new BadRequestException('Billing module is not loaded'); + } + const usecase = this.moduleRef.get(require('@novu/ee-billing')?.StartReverseFreeTrial, { + strict: false, + }); + await usecase.execute({ + userId, + organizationId, + }); + } + } catch (e) { + Logger.error(e, `Unexpected error while importing enterprise modules`, 'StartReverseFreeTrial'); + } + } +} diff --git a/apps/api/src/app/organization/usecases/index.ts b/apps/api/src/app/organization/usecases/index.ts index dc5f9f75b8b..f998aba390a 100644 --- a/apps/api/src/app/organization/usecases/index.ts +++ b/apps/api/src/app/organization/usecases/index.ts @@ -8,6 +8,22 @@ import { UpdateBrandingDetails } from './update-branding-details/update-branding import { GetOrganizations } from './get-organizations/get-organizations.usecase'; import { GetMyOrganization } from './get-my-organization/get-my-organization.usecase'; import { RenameOrganization } from './rename-organization/rename-organization.usecase'; +import { SyncExternalOrganization } from './create-organization/sync-external-organization/sync-external-organization.usecase'; +import { isClerkEnabled } from '@novu/shared'; + +// TODO: move ee.organization.controller.ts to EE package +function getEnterpriseUsecases() { + if (isClerkEnabled()) { + return [ + { + provide: 'SyncOrganizationUsecase', + useClass: SyncExternalOrganization, + }, + ]; + } + + return []; +} export const USE_CASES = [ AddMember, @@ -20,4 +36,5 @@ export const USE_CASES = [ GetOrganizations, GetMyOrganization, RenameOrganization, + ...getEnterpriseUsecases(), ]; diff --git a/apps/api/src/app/rate-limiting/usecases/get-api-rate-limit-maximum/get-api-rate-limit-maximum.spec.ts b/apps/api/src/app/rate-limiting/usecases/get-api-rate-limit-maximum/get-api-rate-limit-maximum.spec.ts index 081c8b49a40..dde0428f54a 100644 --- a/apps/api/src/app/rate-limiting/usecases/get-api-rate-limit-maximum/get-api-rate-limit-maximum.spec.ts +++ b/apps/api/src/app/rate-limiting/usecases/get-api-rate-limit-maximum/get-api-rate-limit-maximum.spec.ts @@ -53,7 +53,7 @@ describe('GetApiRateLimitMaximum', async () => { getDefaultApiRateLimits = moduleRef.get(GetApiRateLimitServiceMaximumConfig); findOneEnvironmentStub = sinon.stub(environmentRepository, 'findOne'); - findOneOrganizationStub = sinon.stub(organizationRepository, 'findOne'); + findOneOrganizationStub = sinon.stub(organizationRepository, 'findById'); defaultApiRateLimits = sinon.stub(getDefaultApiRateLimits, 'default').value(mockDefaultApiRateLimits); }); diff --git a/apps/api/src/app/rate-limiting/usecases/get-api-rate-limit-maximum/get-api-rate-limit-maximum.usecase.ts b/apps/api/src/app/rate-limiting/usecases/get-api-rate-limit-maximum/get-api-rate-limit-maximum.usecase.ts index a907666194c..87a5c3e1f83 100644 --- a/apps/api/src/app/rate-limiting/usecases/get-api-rate-limit-maximum/get-api-rate-limit-maximum.usecase.ts +++ b/apps/api/src/app/rate-limiting/usecases/get-api-rate-limit-maximum/get-api-rate-limit-maximum.usecase.ts @@ -55,7 +55,7 @@ export class GetApiRateLimitMaximum { apiServiceLevel = CUSTOM_API_SERVICE_LEVEL; apiRateLimits = environment.apiRateLimits; } else { - const organization = await this.organizationRepository.findOne({ _id: _organizationId }); + const organization = await this.organizationRepository.findById(_organizationId); if (!organization) { const message = `Organization id: ${_organizationId} not found`; diff --git a/apps/api/src/app/shared/shared.module.ts b/apps/api/src/app/shared/shared.module.ts index cb7e5f6d4be..1ea4d4e8d4f 100644 --- a/apps/api/src/app/shared/shared.module.ts +++ b/apps/api/src/app/shared/shared.module.ts @@ -40,6 +40,7 @@ import { storageService, ExecutionLogRoute, CreateExecutionDetails, + injectRepositories, } from '@novu/application-generic'; import packageJson from '../../../package.json'; @@ -68,6 +69,7 @@ const DAL_MODELS = [ TopicSubscribersRepository, TenantRepository, WorkflowOverrideRepository, + ...injectRepositories(), ]; const dalService = { diff --git a/apps/api/src/app/storage/e2e/get-signed-url.e2e.ts b/apps/api/src/app/storage/e2e/get-signed-url.e2e.ts index 777fccc4204..6efbea21578 100644 --- a/apps/api/src/app/storage/e2e/get-signed-url.e2e.ts +++ b/apps/api/src/app/storage/e2e/get-signed-url.e2e.ts @@ -1,7 +1,7 @@ import { UserSession } from '@novu/testing'; import { expect } from 'chai'; -describe('Get Signed Url - /storage/upload-url (GET)', function () { +describe('Get Signed Url - /storage/upload-url (GET) @skip-in-ee', function () { let session: UserSession; beforeEach(async () => { diff --git a/apps/api/src/app/testing/billing/evaluate-event-resource-limit.e2e-ee.ts b/apps/api/src/app/testing/billing/evaluate-event-resource-limit.e2e-ee.ts index df301a038ed..8ffff33d230 100644 --- a/apps/api/src/app/testing/billing/evaluate-event-resource-limit.e2e-ee.ts +++ b/apps/api/src/app/testing/billing/evaluate-event-resource-limit.e2e-ee.ts @@ -3,15 +3,10 @@ import { expect } from 'chai'; import sinon from 'sinon'; import { Test } from '@nestjs/testing'; import { CacheService, MockCacheService } from '@novu/application-generic'; -import { SharedModule } from '../../shared/shared.module'; import { ApiServiceLevelEnum } from '@novu/shared'; -import { - EvaluateEventResourceLimit, - GetPlatformNotificationUsage, - GetSubscription, - BillingModule, -} from '@novu/ee-billing'; +import { EvaluateEventResourceLimit, GetPlatformNotificationUsage, GetSubscription } from '@novu/ee-billing'; import { randomUUID } from 'node:crypto'; +import { AppModule } from '../../../app.module'; describe('EvaluateEventResourceLimit', async () => { let useCase: EvaluateEventResourceLimit; @@ -24,7 +19,7 @@ describe('EvaluateEventResourceLimit', async () => { beforeEach(async () => { const moduleRef = await Test.createTestingModule({ - imports: [SharedModule, BillingModule.forRoot()], + imports: [AppModule], }) .overrideProvider(CacheService) .useValue(MockCacheService.createClient()) diff --git a/apps/api/src/app/testing/billing/get-platform-notification-usage.e2e-ee.ts b/apps/api/src/app/testing/billing/get-platform-notification-usage.e2e-ee.ts index 50913bf68dc..c9ec0884083 100644 --- a/apps/api/src/app/testing/billing/get-platform-notification-usage.e2e-ee.ts +++ b/apps/api/src/app/testing/billing/get-platform-notification-usage.e2e-ee.ts @@ -1,8 +1,8 @@ import sinon from 'sinon'; import { expect } from 'chai'; -import { NotificationRepository, OrganizationRepository } from '@novu/dal'; +import { EnvironmentRepository, NotificationRepository } from '@novu/dal'; import { UserSession } from '@novu/testing'; -import { ApiServiceLevelEnum } from '@novu/shared'; +import { ApiServiceLevelEnum, isClerkEnabled } from '@novu/shared'; describe('GetPlatformNotificationUsage', () => { const eeBilling = require('@novu/ee-billing'); @@ -12,11 +12,11 @@ describe('GetPlatformNotificationUsage', () => { // eslint-disable-next-line @typescript-eslint/naming-convention const { GetPlatformNotificationUsage, GetPlatformNotificationUsageCommand } = eeBilling; - const organizationRepo = new OrganizationRepository(); + const environmentRepo = new EnvironmentRepository(); const notificationRepo = new NotificationRepository(); const createUseCase = () => { - const useCase = new GetPlatformNotificationUsage(organizationRepo); + const useCase = new GetPlatformNotificationUsage(environmentRepo); return useCase; }; @@ -57,7 +57,9 @@ describe('GetPlatformNotificationUsage', () => { const notificationCountPerIndex = 10; const orgCount = 10; - const orgPromises = new Array(orgCount).fill(null).map(async (_, index) => { + const organizations: any[] = []; + + for (let index = 0; index < orgCount; index++) { const orgSession = new UserSession(); await orgSession.initialize(); @@ -71,16 +73,20 @@ describe('GetPlatformNotificationUsage', () => { ); await orgSession.updateOrganizationServiceLevel(ApiServiceLevelEnum.BUSINESS); - return Promise.resolve({ id: orgSession.organization._id, notificationsCount }); - }); - const organizations = await Promise.all(orgPromises); + organizations.push({ id: orgSession.organization._id, notificationsCount }); + } - const expectedResult = organizations.map((org) => ({ + let expectedResult = organizations.map((org) => ({ _id: org.id.toString(), apiServiceLevel: ApiServiceLevelEnum.BUSINESS, notificationsCount: org.notificationsCount, })); + if (isClerkEnabled()) { + // we have just one organization in Clerk - we don't create new ones on initialize() + expectedResult = [expectedResult[expectedResult.length - 1]]; + } + const result = await useCase.execute( GetPlatformNotificationUsageCommand.create({ startDate: mockStartDate, diff --git a/apps/api/src/app/testing/billing/upsert-subscription.e2e-ee.ts b/apps/api/src/app/testing/billing/upsert-subscription.e2e-ee.ts index 2ec5cfc08cf..9ffe71669bd 100644 --- a/apps/api/src/app/testing/billing/upsert-subscription.e2e-ee.ts +++ b/apps/api/src/app/testing/billing/upsert-subscription.e2e-ee.ts @@ -1,5 +1,5 @@ import sinon from 'sinon'; -import { OrganizationRepository } from '@novu/dal'; +import { CommunityOrganizationRepository } from '@novu/dal'; import { expect } from 'chai'; import { ApiServiceLevelEnum } from '@novu/shared'; import { StripeBillingIntervalEnum, StripeUsageTypeEnum } from '@novu/ee-billing/src/stripe/types'; @@ -24,7 +24,7 @@ describe('UpsertSubscription', () => { let deleteSubscriptionStub: sinon.SinonStub; let getPricesStub: sinon.SinonStub; - const repo = new OrganizationRepository(); + const repo = new CommunityOrganizationRepository(); let updateOrgStub: sinon.SinonStub; const mockCustomerBase = { @@ -615,7 +615,7 @@ describe('UpsertSubscription', () => { expect(updateOrgStub.lastCall.args).to.deep.equal([ { _id: 'organization_id' }, - { apiServiceLevel: ApiServiceLevelEnum.BUSINESS }, + { $set: { apiServiceLevel: ApiServiceLevelEnum.BUSINESS } }, ]); }); }); diff --git a/apps/api/src/app/testing/billing/verify-customer.e2e-ee.ts b/apps/api/src/app/testing/billing/verify-customer.e2e-ee.ts index 92d792a8d19..bc03b92fe63 100644 --- a/apps/api/src/app/testing/billing/verify-customer.e2e-ee.ts +++ b/apps/api/src/app/testing/billing/verify-customer.e2e-ee.ts @@ -4,6 +4,7 @@ import { OrganizationRepository } from '@novu/dal'; import { expect } from 'chai'; import { ApiServiceLevelEnum } from '@novu/shared'; import { VerifyCustomerCommand } from '@novu/ee-billing'; +import { getEERepository } from '@novu/testing'; describe('VerifyCustomer', () => { const eeBilling = require('@novu/ee-billing'); @@ -29,7 +30,7 @@ describe('VerifyCustomer', () => { let getSubscriptionStub: sinon.SinonStub; - const repo = new OrganizationRepository(); + const repo = getEERepository('OrganizationRepository'); let getOrgStub: sinon.SinonStub; beforeEach(() => { diff --git a/apps/api/src/app/testing/billing/webhook.e2e-ee.ts b/apps/api/src/app/testing/billing/webhook.e2e-ee.ts index dcbb76c1a64..bf6068c616e 100644 --- a/apps/api/src/app/testing/billing/webhook.e2e-ee.ts +++ b/apps/api/src/app/testing/billing/webhook.e2e-ee.ts @@ -194,6 +194,7 @@ describe('Stripe webhooks', () => { let verifyCustomerStub: sinon.SinonStub; const organizationRepositoryStub = { update: sinon.stub().resolves({ matched: 1, modified: 1 }), + updateServiceLevel: sinon.stub().resolves({ matched: 1, modified: 1 }), }; const analyticsServiceStub = { track: sinon.stub(), @@ -300,7 +301,7 @@ describe('Stripe webhooks', () => { }); afterEach(() => { - organizationRepositoryStub.update.reset(); + organizationRepositoryStub.updateServiceLevel.reset(); }); const createHandler = () => { @@ -338,12 +339,8 @@ describe('Stripe webhooks', () => { const handler = createHandler(); await handler.handle(event); - expect( - organizationRepositoryStub.update.calledWith( - { _id: 'organization_id' }, - { apiServiceLevel: ApiServiceLevelEnum.BUSINESS } - ) - ).to.be.true; + expect(organizationRepositoryStub.updateServiceLevel.calledWith('organization_id', ApiServiceLevelEnum.BUSINESS)) + .to.be.true; }); it('should exit early with unknown organization', async () => { @@ -375,7 +372,7 @@ describe('Stripe webhooks', () => { const handler = createHandler(); await handler.handle(event); - expect(organizationRepositoryStub.update.called).to.be.false; + expect(organizationRepositoryStub.updateServiceLevel.called).to.be.false; }); it('should handle event with known organization and licensed subscription', async () => { @@ -412,12 +409,8 @@ describe('Stripe webhooks', () => { const handler = createHandler(); await handler.handle(event); - expect( - organizationRepositoryStub.update.calledWith( - { _id: 'organization_id' }, - { apiServiceLevel: ApiServiceLevelEnum.BUSINESS } - ) - ).to.be.true; + expect(organizationRepositoryStub.updateServiceLevel.calledWith('organization_id', ApiServiceLevelEnum.BUSINESS)) + .to.be.true; }); it('should invalidate the subscription cache with known organization and licensed subscription', async () => { @@ -491,12 +484,8 @@ describe('Stripe webhooks', () => { const handler = createHandler(); await handler.handle(event); - expect( - organizationRepositoryStub.update.calledWith( - { _id: 'organization_id' }, - { apiServiceLevel: ApiServiceLevelEnum.BUSINESS } - ) - ).to.be.true; + expect(organizationRepositoryStub.updateServiceLevel.calledWith('organization_id', ApiServiceLevelEnum.BUSINESS)) + .to.be.true; }); it('should exit early with known organization and invalid apiServiceLevel', async () => { @@ -570,7 +559,7 @@ describe('Stripe webhooks', () => { const handler = createHandler(); await handler.handle(event); - expect(organizationRepositoryStub.update.called).to.be.false; + expect(organizationRepositoryStub.updateServiceLevel.called).to.be.false; }); }); }); diff --git a/apps/api/src/app/testing/product-feature.e2e.ts b/apps/api/src/app/testing/product-feature.e2e.ts index 9e5d413cb85..4d582f56d40 100644 --- a/apps/api/src/app/testing/product-feature.e2e.ts +++ b/apps/api/src/app/testing/product-feature.e2e.ts @@ -1,17 +1,17 @@ -import { OrganizationRepository } from '@novu/dal'; +import { CommunityOrganizationRepository } from '@novu/dal'; import { ApiServiceLevelEnum } from '@novu/shared'; import { UserSession } from '@novu/testing'; import { expect } from 'chai'; -describe('Product feature Test', async () => { +describe('Product feature Test @skip-in-ee', async () => { let session: UserSession; const path = '/v1/testing/product-feature'; - let organizationRepository: OrganizationRepository; + let organizationRepository: CommunityOrganizationRepository; beforeEach(async () => { session = new UserSession(); await session.initialize(); - organizationRepository = new OrganizationRepository(); + organizationRepository = new CommunityOrganizationRepository(); }); it('should return a number as response when required api service level exists on organization for feature', async () => { diff --git a/apps/api/src/app/testing/testing.controller.ts b/apps/api/src/app/testing/testing.controller.ts index 5b94b23c86f..103361a93ba 100644 --- a/apps/api/src/app/testing/testing.controller.ts +++ b/apps/api/src/app/testing/testing.controller.ts @@ -18,7 +18,7 @@ import { UserAuthentication } from '../shared/framework/swagger/api.key.security @ApiExcludeController() export class TestingController { constructor( - private seedDataUsecase: SeedData, + // private seedDataUsecase: SeedData, private dalService: DalService, private createSessionUsecase: CreateSession ) {} @@ -46,13 +46,13 @@ export class TestingController { return await this.createSessionUsecase.execute(command); } - @Post('/seed') - async seedData(@Body() body: SeedDataBodyDto): Promise<{ password_user: UserEntity }> { - if (process.env.NODE_ENV !== 'test') throw new NotFoundException(); - const command = SeedDataCommand.create({}); + // @Post('/seed') + // async seedData(@Body() body: SeedDataBodyDto): Promise<{ password_user: UserEntity }> { + // if (process.env.NODE_ENV !== 'test') throw new NotFoundException(); + // const command = SeedDataCommand.create({}); - return await this.seedDataUsecase.execute(command); - } + // return await this.seedDataUsecase.execute(command); + // } @ExternalApiAccessible() @UserAuthentication() diff --git a/apps/api/src/app/testing/translations/update-default-locale.e2e-ee.ts b/apps/api/src/app/testing/translations/update-default-locale.e2e-ee.ts index 8b1e605ab4b..b4ae5db2baa 100644 --- a/apps/api/src/app/testing/translations/update-default-locale.e2e-ee.ts +++ b/apps/api/src/app/testing/translations/update-default-locale.e2e-ee.ts @@ -1,10 +1,10 @@ -import { UserSession } from '@novu/testing'; +import { UserSession, getEERepository } from '@novu/testing'; import { expect } from 'chai'; import { OrganizationRepository } from '@novu/dal'; describe('Update default locale and add new translations - /translations/language (PATCH)', async () => { let session: UserSession; - const organizationRepository = new OrganizationRepository(); + const organizationRepository = getEERepository('OrganizationRepository'); before(async () => { session = new UserSession(); diff --git a/apps/api/src/app/testing/usecases/index.ts b/apps/api/src/app/testing/usecases/index.ts index 289fa8ac809..b6af6cb2405 100644 --- a/apps/api/src/app/testing/usecases/index.ts +++ b/apps/api/src/app/testing/usecases/index.ts @@ -1,4 +1,5 @@ import { SeedData } from './seed-data/seed-data.usecase'; import { CreateSession } from './create-session/create-session.usecase'; -export const USE_CASES = [SeedData, CreateSession]; +// export const USE_CASES = [SeedData, CreateSession]; +export const USE_CASES = [CreateSession]; diff --git a/apps/api/src/app/testing/usecases/seed-data/seed-data.usecase.ts b/apps/api/src/app/testing/usecases/seed-data/seed-data.usecase.ts index 38ed5733854..223e5fead42 100644 --- a/apps/api/src/app/testing/usecases/seed-data/seed-data.usecase.ts +++ b/apps/api/src/app/testing/usecases/seed-data/seed-data.usecase.ts @@ -7,6 +7,7 @@ import { UserRegister } from '../../../auth/usecases/register/user-register.usec import { UserRegisterCommand } from '../../../auth/usecases/register/user-register.command'; import { ApiException } from '../../../shared/exceptions/api.exception'; +// TODO: this causes exit code 1 in ee e2e tests (?) @Injectable() export class SeedData { constructor(private authService: AuthService, private userRegister: UserRegister) {} diff --git a/apps/api/src/app/user/e2e/email-change.e2e.ts b/apps/api/src/app/user/e2e/email-change.e2e.ts index e05b22c0ed4..4ddd2dbbf6b 100644 --- a/apps/api/src/app/user/e2e/email-change.e2e.ts +++ b/apps/api/src/app/user/e2e/email-change.e2e.ts @@ -1,12 +1,9 @@ -import { EnvironmentRepository, OrganizationRepository } from '@novu/dal'; import { UserSession } from '@novu/testing'; import { expect } from 'chai'; -describe('Change Profile Email - /users/profile/email (PUT)', async () => { +describe('Change Profile Email - /users/profile/email (PUT) @skip-in-ee', async () => { let session: UserSession; let existingSession: UserSession; - const environmentRepository = new EnvironmentRepository(); - const organizationRepository = new OrganizationRepository(); before(async () => { session = new UserSession(); diff --git a/apps/api/src/app/user/e2e/get-me.e2e.ts b/apps/api/src/app/user/e2e/get-me.e2e.ts index d53c8067f94..169d6866c17 100644 --- a/apps/api/src/app/user/e2e/get-me.e2e.ts +++ b/apps/api/src/app/user/e2e/get-me.e2e.ts @@ -1,7 +1,7 @@ import { UserSession } from '@novu/testing'; import { expect } from 'chai'; -describe('User Profile', async () => { +describe('User Profile @skip-in-ee', async () => { let session: UserSession; before(async () => { diff --git a/apps/api/src/app/user/e2e/sync-user.e2e-ee.ts b/apps/api/src/app/user/e2e/sync-user.e2e-ee.ts new file mode 100644 index 00000000000..9f455351f96 --- /dev/null +++ b/apps/api/src/app/user/e2e/sync-user.e2e-ee.ts @@ -0,0 +1,72 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +import { UserSession } from '@novu/testing'; +import { expect } from 'chai'; +import { ClerkClientMock } from '@novu/ee-auth'; +import { User } from '@novu/shared'; + +// TODO: rework to clerk webhook +describe.skip('Sync Clerk user with internal database', async () => { + let session: UserSession; + let clerkClientMock: ClerkClientMock; + let clerkUser: User; + + function getRequest(origin: string = process.env.FRONT_BASE_URL) { + return session.testAgent.post('/v1/users/').set('origin', origin); + } + + before(async () => { + session = new UserSession(); + clerkClientMock = new ClerkClientMock(); + + // must be an existing Clerk user + clerkUser = await clerkClientMock.users.getUser('clerk_user_1'); + + await session.updateEETokenClaims({ + _id: clerkUser.id, + email: clerkUser.primaryEmailAddress?.emailAddress, + lastName: clerkUser.lastName!, + firstName: clerkUser.firstName!, + profilePicture: clerkUser.imageUrl, + externalId: clerkUser.externalId!, + }); + }); + + it('should create internal user with externalId of given existing Clerk user', async () => { + const { body } = await getRequest().expect(201); + + const internalUser = body.data; + const updatedClerkUser = await clerkClientMock.users.getUser(clerkUser.id); + + expect(internalUser._id).to.equal(updatedClerkUser.externalId); + expect(internalUser.externalId).to.equal(updatedClerkUser.id); + }); + + it('should throw an error when internal user already exists for Clerk user', async () => { + const { body } = await getRequest().expect(400); + + expect(body.message).to.equal(`Internal user with externalId: ${clerkUser.id} already exists`); + }); + + it('should throw an error when Clerk user does not exist', async () => { + const id = 'not_existing_id'; + await session.updateEETokenClaims({ + _id: id, + email: clerkUser.primaryEmailAddress?.emailAddress, + lastName: clerkUser.lastName!, + firstName: clerkUser.firstName!, + profilePicture: clerkUser.imageUrl, + externalId: clerkUser.externalId!, + }); + + const { body } = await getRequest().expect(400); + + expect(body.message).to.equal(`Clerk user with id: ${id} does not exist`); + }); + + it('should not allow API call from different origin than Novu frontend', async () => { + const origin = 'https://external.com'; + const { body } = await getRequest(origin).expect(403); + + expect(body.message).to.equal('Forbidden'); + }); +}); diff --git a/apps/api/src/app/user/e2e/update-name-and-profile-picture.e2e.ts b/apps/api/src/app/user/e2e/update-name-and-profile-picture.e2e.ts index 81749bcdb2c..3437ac7d403 100644 --- a/apps/api/src/app/user/e2e/update-name-and-profile-picture.e2e.ts +++ b/apps/api/src/app/user/e2e/update-name-and-profile-picture.e2e.ts @@ -1,7 +1,7 @@ import { processTestAgentExpectedStatusCode, UserSession } from '@novu/testing'; import { expect } from 'chai'; -describe('Update user name and profile picture - /users/profile (PUT)', async () => { +describe('Update user name and profile picture - /users/profile (PUT) @skip-in-ee', async () => { let session: UserSession; before(async () => { diff --git a/apps/api/src/app/user/usecases/index.ts b/apps/api/src/app/user/usecases/index.ts index 57c04f8fbe5..19dfab02495 100644 --- a/apps/api/src/app/user/usecases/index.ts +++ b/apps/api/src/app/user/usecases/index.ts @@ -1,10 +1,19 @@ import { CreateUser } from '@novu/application-generic'; - +import { isClerkEnabled } from '@novu/shared'; import { GetMyProfileUsecase } from './get-my-profile/get-my-profile.usecase'; import { UpdateOnBoardingUsecase } from './update-on-boarding/update-on-boarding.usecase'; import { UpdateOnBoardingTourUsecase } from './update-on-boarding-tour/update-on-boarding-tour.usecase'; import { UpdateProfileEmail } from './update-profile-email/update-profile-email.usecase'; import { UpdateNameAndProfilePicture } from './update-name-and-profile-picture/update-name-and-profile-picture.usecase'; +import { SyncExternalUser } from './sync-external-user/sync-external-user.usecase'; + +function getEnterpriseUsecases() { + if (isClerkEnabled()) { + return [SyncExternalUser]; + } + + return []; +} export const USE_CASES = [ CreateUser, @@ -13,4 +22,5 @@ export const USE_CASES = [ UpdateProfileEmail, UpdateOnBoardingTourUsecase, UpdateNameAndProfilePicture, + ...getEnterpriseUsecases(), ]; diff --git a/apps/api/src/app/user/usecases/sync-external-user/sync-external-user.command.ts b/apps/api/src/app/user/usecases/sync-external-user/sync-external-user.command.ts new file mode 100644 index 00000000000..6ad9a5f60f8 --- /dev/null +++ b/apps/api/src/app/user/usecases/sync-external-user/sync-external-user.command.ts @@ -0,0 +1,3 @@ +import { AuthenticatedCommand } from '@novu/application-generic'; + +export class SyncExternalUserCommand extends AuthenticatedCommand {} diff --git a/apps/api/src/app/user/usecases/sync-external-user/sync-external-user.usecase.ts b/apps/api/src/app/user/usecases/sync-external-user/sync-external-user.usecase.ts new file mode 100644 index 00000000000..2a2c4b3fe74 --- /dev/null +++ b/apps/api/src/app/user/usecases/sync-external-user/sync-external-user.usecase.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@nestjs/common'; +import { InstrumentUsecase } from '@novu/application-generic'; +import { UserEntity, UserRepository } from '@novu/dal'; +import { SyncExternalUserCommand } from './sync-external-user.command'; + +@Injectable() +export class SyncExternalUser { + constructor(private readonly userRepository: UserRepository) {} + + @InstrumentUsecase() + public async execute(command: SyncExternalUserCommand): Promise { + return this.userRepository.create({}, { linkOnly: true, externalId: command.userId }); + } +} diff --git a/apps/api/src/app/widgets/e2e/get-count.e2e.ts b/apps/api/src/app/widgets/e2e/get-count.e2e.ts index 07bd85d2f0c..8cc287fb3de 100644 --- a/apps/api/src/app/widgets/e2e/get-count.e2e.ts +++ b/apps/api/src/app/widgets/e2e/get-count.e2e.ts @@ -70,7 +70,6 @@ describe('Count - GET /widget/notifications/count', function () { String(subscriberProfile?._id), ChannelTypeEnum.IN_APP ); - const messageId = messages[0]._id; const seenCount = (await getFeedCount()).data.count; expect(seenCount).to.equal(3); }); diff --git a/apps/api/src/app/workflows/e2e/create-notification-templates.e2e.ts b/apps/api/src/app/workflows/e2e/create-notification-templates.e2e.ts index 612a0e542ac..e32e80ce295 100644 --- a/apps/api/src/app/workflows/e2e/create-notification-templates.e2e.ts +++ b/apps/api/src/app/workflows/e2e/create-notification-templates.e2e.ts @@ -14,6 +14,7 @@ import { EmailProviderIdEnum, ChangeEntityTypeEnum, INotificationTemplateStep, + isClerkEnabled, WorkflowTypeEnum, } from '@novu/shared'; import { @@ -24,6 +25,7 @@ import { SubscriberEntity, OrganizationRepository, NotificationTemplateEntity, + CommunityOrganizationRepository, } from '@novu/dal'; import { isSameDay } from 'date-fns'; import { CreateWorkflowRequestDto } from '../dto'; @@ -510,7 +512,9 @@ describe('Create Notification template from blueprint - /notification-templates let session: UserSession; const notificationTemplateRepository: NotificationTemplateRepository = new NotificationTemplateRepository(); const environmentRepository: EnvironmentRepository = new EnvironmentRepository(); - const organizationRepository: OrganizationRepository = new OrganizationRepository(); + const organizationRepository: OrganizationRepository = new OrganizationRepository( + new CommunityOrganizationRepository() + ); before(async () => { session = new UserSession(); @@ -546,8 +550,14 @@ describe('Create Notification template from blueprint - /notification-templates const { blueprintId } = await buildBlueprint(session, prodEnv, notificationTemplateRepository); const blueprint = (await session.testAgent.get(`/v1/blueprints/${blueprintId}`).send()).body.data; - const blueprintOrg = await organizationRepository.create({ name: 'Blueprint Org' }); - process.env.BLUEPRINT_CREATOR = blueprintOrg._id; + + if (isClerkEnabled()) { + process.env.BLUEPRINT_CREATOR = session.organization._id; + } else { + const blueprintOrg = await organizationRepository.create({ name: 'Blueprint Org' }); + process.env.BLUEPRINT_CREATOR = blueprintOrg._id; + } + blueprint.notificationGroupId = blueprint._notificationGroupId; blueprint.notificationGroup.name = 'New Group Name'; blueprint.blueprintId = blueprint._id; diff --git a/apps/api/src/bootstrap.ts b/apps/api/src/bootstrap.ts index f2facf26ad6..7f7abffd753 100644 --- a/apps/api/src/bootstrap.ts +++ b/apps/api/src/bootstrap.ts @@ -50,22 +50,19 @@ validateEnv(); export async function bootstrap(expressApp?): Promise { BullMqService.haveProInstalled(); - let rawBodyBuffer: undefined | (() => void) = undefined; + let rawBodyBuffer: undefined | ((...args) => void) = undefined; let nestOptions: Record = {}; - try { - if ( - (process.env.NOVU_ENTERPRISE === 'true' && require('@novu/ee-billing')?.rawBodyBuffer) || - process.env.CI_EE_TEST === 'true' - ) { - rawBodyBuffer = require('@novu/ee-billing')?.rawBodyBuffer; - nestOptions = { - bodyParser: false, - rawBody: true, - }; - } - } catch (e) { - Logger.error(e, `Unexpected error while importing enterprise modules`, 'EnterpriseImport'); + if (process.env.NOVU_ENTERPRISE === 'true' || process.env.CI_EE_TEST === 'true') { + rawBodyBuffer = (req, res, buffer, encoding): void => { + if (buffer && buffer.length) { + req.rawBody = Buffer.from(buffer); + } + }; + nestOptions = { + bodyParser: false, + rawBody: true, + }; } let app: INestApplication; diff --git a/apps/api/src/metadata.ts b/apps/api/src/metadata.ts index 0d895409d9b..1924768a322 100644 --- a/apps/api/src/metadata.ts +++ b/apps/api/src/metadata.ts @@ -2001,6 +2001,18 @@ export default async () => { }, }, ], + [ + import('./app/organization/ee.organization.controller'), + { + EEOrganizationController: { + getMyOrganization: { + type: t['../../../libs/dal/dist/repositories/organization/organization.entity'].OrganizationEntity, + }, + updateBrandingDetails: {}, + renameOrganization: {}, + }, + }, + ], [ import('./app/testing/testing.controller'), { @@ -2011,7 +2023,6 @@ export default async () => { 'Used for seeding data for client e2e tests,\nCurrently just creates a new user session and returns signed JWT', type: Object, }, - seedData: {}, idempotency: {}, idempotencyGet: {}, productFeatureGet: {}, @@ -2368,6 +2379,10 @@ export default async () => { }, }, ], + [ + import('./app/auth/legacy-ee-auth/auth.controller'), + { AuthController: { googleAuth: {}, googleCallback: { type: Object } } }, + ], ], }, }; diff --git a/apps/webhook/src/shared/shared.module.ts b/apps/webhook/src/shared/shared.module.ts index 57edb4a90a7..02e1c4a1854 100644 --- a/apps/webhook/src/shared/shared.module.ts +++ b/apps/webhook/src/shared/shared.module.ts @@ -1,5 +1,5 @@ import { Module } from '@nestjs/common'; -import { AnalyticsService } from '@novu/application-generic'; +import { AnalyticsService, injectRepositories } from '@novu/application-generic'; import { DalService, UserRepository, @@ -27,6 +27,7 @@ const DAL_MODELS = [ MemberRepository, IntegrationRepository, JobRepository, + ...injectRepositories(), ]; const dalService = new DalService(); diff --git a/apps/worker/src/app/shared/shared.module.ts b/apps/worker/src/app/shared/shared.module.ts index 2ee052890c5..c3c154c4542 100644 --- a/apps/worker/src/app/shared/shared.module.ts +++ b/apps/worker/src/app/shared/shared.module.ts @@ -51,6 +51,7 @@ import { UpdateSubscriber, UpdateSubscriberChannel, UpdateTenant, + injectRepositories, } from '@novu/application-generic'; import packageJson from '../../../package.json'; @@ -82,6 +83,7 @@ const DAL_MODELS = [ TopicSubscribersRepository, TenantRepository, WorkflowOverrideRepository, + ...injectRepositories(), ]; const dalService = { diff --git a/apps/ws/src/shared/shared.module.ts b/apps/ws/src/shared/shared.module.ts index c104345f229..67ac3b0e719 100644 --- a/apps/ws/src/shared/shared.module.ts +++ b/apps/ws/src/shared/shared.module.ts @@ -16,6 +16,7 @@ import { DalServiceHealthIndicator, WebSocketsInMemoryProviderService, QueuesModule, + injectRepositories, } from '@novu/application-generic'; import { SubscriberOnlineService } from './subscriber-online'; @@ -30,6 +31,7 @@ const DAL_MODELS = [ NotificationRepository, MessageRepository, MemberRepository, + ...injectRepositories(), ]; const dalService = { diff --git a/apps/ws/src/socket/usecases/external-services-route/external-services-route.spec.ts b/apps/ws/src/socket/usecases/external-services-route/external-services-route.spec.ts index 7d16546068f..82b69848c00 100644 --- a/apps/ws/src/socket/usecases/external-services-route/external-services-route.spec.ts +++ b/apps/ws/src/socket/usecases/external-services-route/external-services-route.spec.ts @@ -1,14 +1,15 @@ import sinon from 'sinon'; -import { EnvironmentRepository, MessageEntity, MessageRepository, UserRepository } from '@novu/dal'; +import { MessageEntity, MessageRepository } from '@novu/dal'; import { WebSocketEventEnum } from '@novu/shared'; import { ExternalServicesRoute } from './external-services-route.usecase'; import { ExternalServicesRouteCommand } from './external-services-route.command'; import { WSGateway } from '../../ws.gateway'; +import { Types } from 'mongoose'; -const environmentId = EnvironmentRepository.createObjectId(); +const environmentId = new Types.ObjectId().toString(); const messageId = 'message-id-1'; -const userId = UserRepository.createObjectId(); +const userId = new Types.ObjectId().toString(); const commandReceivedMessage = ExternalServicesRouteCommand.create({ event: WebSocketEventEnum.RECEIVED, diff --git a/enterprise/packages/auth/package.json b/enterprise/packages/auth/package.json index 8b036ee9694..ed8d307dea2 100644 --- a/enterprise/packages/auth/package.json +++ b/enterprise/packages/auth/package.json @@ -12,28 +12,35 @@ "test-ee": "cross-env TS_NODE_COMPILER_OPTIONS='{\"strictNullChecks\": false}' NODE_ENV=test E2E_RUNNER=true mocha --timeout 10000 --require ts-node/register --exit --file tests/setup.ts src/**/**/*.spec.ts" }, "dependencies": { - "@novu/application-generic": "workspace:*", + "@clerk/clerk-sdk-node": "^5.0.9", "@novu/dal": "workspace:*", "@novu/shared": "workspace:*", - "passport-google-oauth": "^2.0.0" + "mongoose": "^7.5.0", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.0", + "jwks-rsa": "^3.1.0", + "svix": "^1.24.0" }, "devDependencies": { - "@types/chai": "^4.2.11", + "@clerk/types": "^4.5.1", "@types/mocha": "^8.0.1", "@types/node": "^20.14.10", - "@types/sinon": "^9.0.0", - "chai": "^4.2.0", + "@types/passport-jwt": "^3.0.3", "cross-env": "^7.0.3", "mocha": "^8.1.1", + "@types/sinon": "^9.0.0", + "chai": "^4.2.0", "sinon": "^9.2.4", "ts-node": "~10.9.1", "typescript": "4.9.5" }, "peerDependencies": { "@nestjs/common": "10.2.2", + "@nestjs/core": ">=10", "@nestjs/jwt": "10.2.0", "@nestjs/passport": "9.0.3", + "@nestjs/swagger": "^7.1.9", "passport": "0.6.0", - "passport-oauth2": "^1.6.1" + "passport-jwt": "^4.0.0" } } diff --git a/enterprise/packages/auth/tsconfig.json b/enterprise/packages/auth/tsconfig.json index 924ec33b4eb..e0d20083c8f 100644 --- a/enterprise/packages/auth/tsconfig.json +++ b/enterprise/packages/auth/tsconfig.json @@ -8,7 +8,7 @@ "esModuleInterop": true, "rootDir": "src", "strict": true, - "types": ["node", "mocha", "chai", "sinon"], + "types": ["node", "mocha"], "skipLibCheck": true, "typeRoots": ["./node_modules/@types", "../../node_modules/@types"] }, diff --git a/libs/application-generic/package.json b/libs/application-generic/package.json index 752fbfe3761..d560cdec1d2 100644 --- a/libs/application-generic/package.json +++ b/libs/application-generic/package.json @@ -97,6 +97,7 @@ "slugify": "^1.4.6" }, "optionalDependencies": { + "@novu/ee-auth": "workspace:*", "@novu/ee-bridge-worker": "workspace:*", "@novu/ee-shared-services": "workspace:*", "@taskforcesh/bullmq-pro": "5.1.14" diff --git a/libs/application-generic/src/index.ts b/libs/application-generic/src/index.ts index 79f47bb990e..42beb44a8fc 100644 --- a/libs/application-generic/src/index.ts +++ b/libs/application-generic/src/index.ts @@ -9,6 +9,7 @@ export * from './health/index'; export * from './instrumentation/index'; export * from './logging/index'; export * from './modules'; +export * from './utils/inject-repositories'; export * from './profiling'; export * from './resilience'; export * from './services'; diff --git a/libs/application-generic/src/services/auth/auth.service.interface.ts b/libs/application-generic/src/services/auth/auth.service.interface.ts new file mode 100644 index 00000000000..d91825f52b2 --- /dev/null +++ b/libs/application-generic/src/services/auth/auth.service.interface.ts @@ -0,0 +1,42 @@ +import { SubscriberEntity, UserEntity, MemberEntity } from '@novu/dal'; +import { + AuthProviderEnum, + SignUpOriginEnum, + ISubscriberJwt, + UserSessionData, +} from '@novu/shared'; + +export interface IAuthService { + authenticate( + authProvider: AuthProviderEnum, + accessToken: string, + refreshToken: string, + profile: { + name: string; + login: string; + email: string; + avatar_url: string; + id: string; + }, + distinctId: string, + origin?: SignUpOriginEnum + ): Promise<{ newUser: boolean; token: string }>; + refreshToken(userId: string): Promise; + isAuthenticatedForOrganization( + userId: string, + organizationId: string + ): Promise; + getUserByApiKey(apiKey: string): Promise; + getSubscriberWidgetToken(subscriber: SubscriberEntity): Promise; + generateUserToken(user: UserEntity): Promise; + getSignedToken( + user: UserEntity, + organizationId?: string, + member?: MemberEntity, + environmentId?: string + ): Promise; + + validateUser(payload: UserSessionData): Promise; + validateSubscriber(payload: ISubscriberJwt): Promise; + isRootEnvironment(payload: UserSessionData): Promise; +} diff --git a/libs/application-generic/src/services/auth/auth.service.ts b/libs/application-generic/src/services/auth/auth.service.ts index 7d34fd78a2f..98b29828879 100644 --- a/libs/application-generic/src/services/auth/auth.service.ts +++ b/libs/application-generic/src/services/auth/auth.service.ts @@ -1,70 +1,18 @@ -import { createHash } from 'crypto'; -import { - forwardRef, - Inject, - Injectable, - NotFoundException, - UnauthorizedException, -} from '@nestjs/common'; -import { JwtService } from '@nestjs/jwt'; - -import { - EnvironmentEntity, - EnvironmentRepository, - MemberEntity, - MemberRepository, - OrganizationRepository, - SubscriberEntity, - SubscriberRepository, - UserEntity, - UserRepository, -} from '@novu/dal'; +import { Inject, Injectable } from '@nestjs/common'; +import { SubscriberEntity, UserEntity, MemberEntity } from '@novu/dal'; import { AuthProviderEnum, - ISubscriberJwt, - MemberRoleEnum, SignUpOriginEnum, + ISubscriberJwt, UserSessionData, } from '@novu/shared'; - -import { AnalyticsService } from '../analytics.service'; -import { ApiException } from '../../utils/exceptions'; -import { Instrument } from '../../instrumentation'; -import { CreateUser, CreateUserCommand } from '../../usecases/create-user'; -import { - SwitchEnvironment, - SwitchEnvironmentCommand, -} from '../../usecases/switch-environment'; -import { - SwitchOrganization, - SwitchOrganizationCommand, -} from '../../usecases/switch-organization'; -import { - buildAuthServiceKey, - buildSubscriberKey, - buildUserKey, - CachedEntity, -} from '../cache'; -import { normalizeEmail } from '@novu/shared'; +import { IAuthService } from './auth.service.interface'; @Injectable() -export class AuthService { - constructor( - private userRepository: UserRepository, - private subscriberRepository: SubscriberRepository, - private createUserUsecase: CreateUser, - private jwtService: JwtService, - private analyticsService: AnalyticsService, - private organizationRepository: OrganizationRepository, - private environmentRepository: EnvironmentRepository, - private memberRepository: MemberRepository, - @Inject(forwardRef(() => SwitchOrganization)) - private switchOrganizationUsecase: SwitchOrganization, - @Inject(forwardRef(() => SwitchEnvironment)) - private switchEnvironmentUsecase: SwitchEnvironment - ) {} +export class AuthService implements IAuthService { + constructor(@Inject('AUTH_SERVICE') private authService: IAuthService) {} - public async authenticate( + authenticate( authProvider: AuthProviderEnum, accessToken: string, refreshToken: string, @@ -77,347 +25,66 @@ export class AuthService { }, distinctId: string, origin?: SignUpOriginEnum - ) { - const email = normalizeEmail(profile.email); - let user = await this.userRepository.findByEmail(email); - let newUser = false; - - if (!user) { - const firstName = profile.name - ? profile.name.split(' ').slice(0, -1).join(' ') - : profile.login; - const lastName = profile.name - ? profile.name.split(' ').slice(-1).join(' ') - : null; - - user = await this.createUserUsecase.execute( - CreateUserCommand.create({ - picture: profile.avatar_url, - email, - firstName, - lastName, - auth: { - username: profile.login, - profileId: profile.id, - provider: authProvider, - accessToken, - refreshToken, - }, - }) - ); - newUser = true; - - if (distinctId) { - this.analyticsService.alias(distinctId, user._id); - } - - this.analyticsService.track('[Authentication] - Signup', user._id, { - loginType: authProvider, - origin: origin, - }); - } else { - if ( - authProvider === AuthProviderEnum.GITHUB || - authProvider === AuthProviderEnum.GOOGLE - ) { - user = await this.updateUserUsername(user, profile, authProvider); - } - - this.analyticsService.track('[Authentication] - Login', user._id, { - loginType: authProvider, - }); - } - - this.analyticsService.upsertUser(user, user._id); - - return { - newUser, - token: await this.generateUserToken(user), - }; - } - - private async updateUserUsername( - user: UserEntity, - profile: { - name: string; - login: string; - email: string; - avatar_url: string; - id: string; - }, - authProvider: AuthProviderEnum - ) { - const withoutUsername = user.tokens.find( - (token) => - token.provider === authProvider && - !token.username && - String(token.providerId) === String(profile.id) + ): Promise<{ newUser: boolean; token: string }> { + return this.authService.authenticate( + authProvider, + accessToken, + refreshToken, + profile, + distinctId, + origin ); - - if (withoutUsername) { - await this.userRepository.update( - { - _id: user._id, - 'tokens.providerId': profile.id, - }, - { - $set: { - 'tokens.$.username': profile.login, - }, - } - ); - - user = await this.userRepository.findById(user._id); - if (!user) throw new ApiException('User not found'); - } - - return user; } - public async refreshToken(userId: string) { - const user = await this.getUser({ _id: userId }); - if (!user) throw new UnauthorizedException('User not found'); - - return this.getSignedToken(user); + refreshToken(userId: string): Promise { + return this.authService.refreshToken(userId); } - @Instrument() - public async isAuthenticatedForOrganization( + isAuthenticatedForOrganization( userId: string, organizationId: string ): Promise { - return !!(await this.memberRepository.isMemberOfOrganization( - organizationId, - userId - )); + return this.authService.isAuthenticatedForOrganization( + userId, + organizationId + ); } - @Instrument() - public async getUserByApiKey(apiKey: string): Promise { - const { environment, user, error } = await this.getApiKeyUser({ - apiKey, - }); - - if (error) throw new UnauthorizedException(error); - - return { - _id: user._id, - firstName: user.firstName, - lastName: user.lastName, - email: user.email, - profilePicture: user.profilePicture, - roles: [MemberRoleEnum.ADMIN], - organizationId: environment._organizationId, - environmentId: environment._id, - exp: 0, - }; + getUserByApiKey(apiKey: string): Promise { + return this.authService.getUserByApiKey(apiKey); } - public async getSubscriberWidgetToken( - subscriber: SubscriberEntity - ): Promise { - return this.jwtService.sign( - { - _id: subscriber._id, - firstName: subscriber.firstName, - lastName: subscriber.lastName, - email: subscriber.email, - organizationId: subscriber._organizationId, - environmentId: subscriber._environmentId, - subscriberId: subscriber.subscriberId, - }, - { - expiresIn: '15 day', - issuer: 'novu_api', - audience: 'widget_user', - } - ); + getSubscriberWidgetToken(subscriber: SubscriberEntity): Promise { + return this.authService.getSubscriberWidgetToken(subscriber); } - public async generateUserToken(user: UserEntity) { - const userActiveOrganizations = - await this.organizationRepository.findUserActiveOrganizations(user._id); - - if (userActiveOrganizations && userActiveOrganizations.length) { - const organizationToSwitch = userActiveOrganizations[0]; - - const userActiveProjects = - await this.environmentRepository.findOrganizationEnvironments( - organizationToSwitch._id - ); - let environmentToSwitch = userActiveProjects[0]; - - const reduceEnvsToOnlyDevelopment = (prev, current) => - current.name === 'Development' ? current : prev; - - if (userActiveProjects.length > 1) { - environmentToSwitch = userActiveProjects.reduce( - reduceEnvsToOnlyDevelopment, - environmentToSwitch - ); - } - - if (environmentToSwitch) { - return await this.switchEnvironmentUsecase.execute( - SwitchEnvironmentCommand.create({ - newEnvironmentId: environmentToSwitch._id, - organizationId: organizationToSwitch._id, - userId: user._id, - }) - ); - } - - return await this.switchOrganizationUsecase.execute( - SwitchOrganizationCommand.create({ - newOrganizationId: organizationToSwitch._id, - userId: user._id, - }) - ); - } - - return this.getSignedToken(user); + generateUserToken(user: UserEntity): Promise { + return this.authService.generateUserToken(user); } - public async getSignedToken( + getSignedToken( user: UserEntity, organizationId?: string, member?: MemberEntity, environmentId?: string ): Promise { - const roles: MemberRoleEnum[] = []; - if (member && member.roles) { - roles.push(...member.roles); - } - - return this.jwtService.sign( - { - _id: user._id, - firstName: user.firstName, - lastName: user.lastName, - email: user.email, - profilePicture: user.profilePicture, - organizationId: organizationId || null, - roles, - environmentId: environmentId || null, - }, - { - expiresIn: '30 days', - issuer: 'novu_api', - } + return this.authService.getSignedToken( + user, + organizationId, + member, + environmentId ); } - @Instrument() - public async validateUser(payload: UserSessionData): Promise { - // We run these in parallel to speed up the query time - const userPromise = this.getUser({ _id: payload._id }); - const isMemberPromise = payload.organizationId - ? this.isAuthenticatedForOrganization(payload._id, payload.organizationId) - : Promise.resolve(true); - const [user, isMember] = await Promise.all([userPromise, isMemberPromise]); - - if (!user) throw new UnauthorizedException('User not found'); - if (payload.organizationId && !isMember) { - throw new UnauthorizedException( - `Not authorized for organization ${payload.organizationId}` - ); - } - - return user; + validateUser(payload: UserSessionData): Promise { + return this.authService.validateUser(payload); } - public async validateSubscriber( - payload: ISubscriberJwt - ): Promise { - return await this.getSubscriber({ - _environmentId: payload.environmentId, - subscriberId: payload.subscriberId, - }); + validateSubscriber(payload: ISubscriberJwt): Promise { + return this.authService.validateSubscriber(payload); } - public async isRootEnvironment(payload: UserSessionData): Promise { - const environment = await this.environmentRepository.findOne({ - _id: payload.environmentId, - }); - if (!environment) throw new NotFoundException('Environment not found'); - - return !!environment._parentId; - } - - @Instrument() - @CachedEntity({ - builder: (command: { _id: string }) => - buildUserKey({ - _id: command._id, - }), - }) - private async getUser({ _id }: { _id: string }) { - return await this.userRepository.findById(_id); - } - - @CachedEntity({ - builder: (command: { subscriberId: string; _environmentId: string }) => - buildSubscriberKey({ - _environmentId: command._environmentId, - subscriberId: command.subscriberId, - }), - }) - private async getSubscriber({ - subscriberId, - _environmentId, - }: { - subscriberId: string; - _environmentId: string; - }): Promise { - return await this.subscriberRepository.findBySubscriberId( - _environmentId, - subscriberId - ); - } - - @CachedEntity({ - builder: ({ apiKey }: { apiKey: string }) => - buildAuthServiceKey({ - apiKey: apiKey, - }), - }) - private async getApiKeyUser({ apiKey }: { apiKey: string }): Promise<{ - environment?: EnvironmentEntity; - user?: UserEntity; - error?: string; - }> { - const hashedApiKey = createHash('sha256').update(apiKey).digest('hex'); - - const environment = await this.environmentRepository.findByApiKey({ - key: apiKey, - hash: hashedApiKey, - }); - - if (!environment) { - // Failed to find the environment for the provided API key. - return { error: 'API Key not found' }; - } - - let key = environment.apiKeys.find((i) => i.hash === hashedApiKey); - - if (!key) { - /* - * backward compatibility - delete after encrypt-api-keys-migration execution - * find by decrypted key if key not found, because of backward compatibility - * use-case: findByApiKey found by decrypted key, so we need to validate by decrypted key - */ - key = environment.apiKeys.find((i) => i.key === apiKey); - } - - if (!key) { - return { error: 'API Key not found' }; - } - - const user = await this.userRepository.findById(key._userId); - if (!user) { - return { error: 'User not found' }; - } - - return { environment, user }; + isRootEnvironment(payload: UserSessionData): Promise { + return this.authService.isRootEnvironment(payload); } } diff --git a/libs/application-generic/src/services/auth/community.auth.service.ts b/libs/application-generic/src/services/auth/community.auth.service.ts new file mode 100644 index 00000000000..89660e86920 --- /dev/null +++ b/libs/application-generic/src/services/auth/community.auth.service.ts @@ -0,0 +1,424 @@ +import { createHash } from 'crypto'; +import { + forwardRef, + Inject, + Injectable, + NotFoundException, + UnauthorizedException, +} from '@nestjs/common'; +import { JwtService } from '@nestjs/jwt'; + +import { + EnvironmentRepository, + MemberEntity, + MemberRepository, + OrganizationRepository, + SubscriberEntity, + SubscriberRepository, + UserEntity, + UserRepository, + EnvironmentEntity, +} from '@novu/dal'; +import { + AuthProviderEnum, + UserSessionData, + ISubscriberJwt, + MemberRoleEnum, + SignUpOriginEnum, +} from '@novu/shared'; + +import { AnalyticsService } from '../analytics.service'; +import { ApiException } from '../../utils/exceptions'; +import { Instrument } from '../../instrumentation'; +import { CreateUser, CreateUserCommand } from '../../usecases/create-user'; +import { + SwitchEnvironment, + SwitchEnvironmentCommand, +} from '../../usecases/switch-environment'; +import { + SwitchOrganization, + SwitchOrganizationCommand, +} from '../../usecases/switch-organization'; +import { + buildAuthServiceKey, + buildSubscriberKey, + buildUserKey, + CachedEntity, +} from '../cache'; +import { normalizeEmail } from '@novu/shared'; +import { IAuthService } from './auth.service.interface'; + +@Injectable() +export class CommunityAuthService implements IAuthService { + constructor( + private userRepository: UserRepository, + private subscriberRepository: SubscriberRepository, + private createUserUsecase: CreateUser, + private jwtService: JwtService, + private analyticsService: AnalyticsService, + private organizationRepository: OrganizationRepository, + private environmentRepository: EnvironmentRepository, + private memberRepository: MemberRepository, + @Inject(forwardRef(() => SwitchOrganization)) + private switchOrganizationUsecase: SwitchOrganization, + @Inject(forwardRef(() => SwitchEnvironment)) + private switchEnvironmentUsecase: SwitchEnvironment + ) {} + + public async authenticate( + authProvider: AuthProviderEnum, + accessToken: string, + refreshToken: string, + profile: { + name: string; + login: string; + email: string; + avatar_url: string; + id: string; + }, + distinctId: string, + origin?: SignUpOriginEnum + ) { + const email = normalizeEmail(profile.email); + let user = await this.userRepository.findByEmail(email); + let newUser = false; + + if (!user) { + const firstName = profile.name + ? profile.name.split(' ').slice(0, -1).join(' ') + : profile.login; + const lastName = profile.name + ? profile.name.split(' ').slice(-1).join(' ') + : null; + + user = await this.createUserUsecase.execute( + CreateUserCommand.create({ + picture: profile.avatar_url, + email, + firstName, + lastName, + auth: { + username: profile.login, + profileId: profile.id, + provider: authProvider, + accessToken, + refreshToken, + }, + }) + ); + newUser = true; + + if (distinctId) { + this.analyticsService.alias(distinctId, user._id); + } + + this.analyticsService.track('[Authentication] - Signup', user._id, { + loginType: authProvider, + origin: origin, + }); + } else { + if ( + authProvider === AuthProviderEnum.GITHUB || + authProvider === AuthProviderEnum.GOOGLE + ) { + user = await this.updateUserUsername(user, profile, authProvider); + } + + this.analyticsService.track('[Authentication] - Login', user._id, { + loginType: authProvider, + }); + } + + this.analyticsService.upsertUser(user, user._id); + + return { + newUser, + token: await this.generateUserToken(user), + }; + } + + private async updateUserUsername( + user: UserEntity, + profile: { + name: string; + login: string; + email: string; + avatar_url: string; + id: string; + }, + authProvider: AuthProviderEnum + ) { + const withoutUsername = user.tokens.find( + (token) => + token.provider === authProvider && + !token.username && + String(token.providerId) === String(profile.id) + ); + + if (withoutUsername) { + await this.userRepository.update( + { + _id: user._id, + 'tokens.providerId': profile.id, + }, + { + $set: { + 'tokens.$.username': profile.login, + }, + } + ); + + user = await this.userRepository.findById(user._id); + if (!user) throw new ApiException('User not found'); + } + + return user; + } + + public async refreshToken(userId: string) { + const user = await this.getUser({ _id: userId }); + if (!user) throw new UnauthorizedException('User not found'); + + return this.getSignedToken(user); + } + + @Instrument() + public async isAuthenticatedForOrganization( + userId: string, + organizationId: string + ): Promise { + return !!(await this.memberRepository.isMemberOfOrganization( + organizationId, + userId + )); + } + + @Instrument() + public async getUserByApiKey(apiKey: string): Promise { + const { environment, user, error } = await this.getApiKeyUser({ + apiKey, + }); + + if (error) throw new UnauthorizedException(error); + + return { + _id: user._id, + firstName: user.firstName, + lastName: user.lastName, + email: user.email, + profilePicture: user.profilePicture, + roles: [MemberRoleEnum.ADMIN], + organizationId: environment._organizationId, + environmentId: environment._id, + exp: 0, + }; + } + + public async getSubscriberWidgetToken( + subscriber: SubscriberEntity + ): Promise { + return this.jwtService.sign( + { + _id: subscriber._id, + firstName: subscriber.firstName, + lastName: subscriber.lastName, + email: subscriber.email, + organizationId: subscriber._organizationId, + environmentId: subscriber._environmentId, + subscriberId: subscriber.subscriberId, + }, + { + expiresIn: '15 day', + issuer: 'novu_api', + audience: 'widget_user', + } + ); + } + + public async generateUserToken(user: UserEntity) { + const userActiveOrganizations = + await this.organizationRepository.findUserActiveOrganizations(user._id); + + if (userActiveOrganizations && userActiveOrganizations.length) { + const organizationToSwitch = userActiveOrganizations[0]; + + const userActiveProjects = + await this.environmentRepository.findOrganizationEnvironments( + organizationToSwitch._id + ); + let environmentToSwitch = userActiveProjects[0]; + + const reduceEnvsToOnlyDevelopment = (prev, current) => + current.name === 'Development' ? current : prev; + + if (userActiveProjects.length > 1) { + environmentToSwitch = userActiveProjects.reduce( + reduceEnvsToOnlyDevelopment, + environmentToSwitch + ); + } + + if (environmentToSwitch) { + return await this.switchEnvironmentUsecase.execute( + SwitchEnvironmentCommand.create({ + newEnvironmentId: environmentToSwitch._id, + organizationId: organizationToSwitch._id, + userId: user._id, + }) + ); + } + + return await this.switchOrganizationUsecase.execute( + SwitchOrganizationCommand.create({ + newOrganizationId: organizationToSwitch._id, + userId: user._id, + }) + ); + } + + return this.getSignedToken(user); + } + + public async getSignedToken( + user: UserEntity, + organizationId?: string, + member?: MemberEntity, + environmentId?: string + ): Promise { + const roles: MemberRoleEnum[] = []; + if (member && member.roles) { + roles.push(...member.roles); + } + + return this.jwtService.sign( + { + _id: user._id, + firstName: user.firstName, + lastName: user.lastName, + email: user.email, + profilePicture: user.profilePicture, + organizationId: organizationId || null, + roles, + environmentId: environmentId || null, + }, + { + expiresIn: '30 days', + issuer: 'novu_api', + } + ); + } + + @Instrument() + public async validateUser(payload: UserSessionData): Promise { + // We run these in parallel to speed up the query time + const userPromise = this.getUser({ _id: payload._id }); + const isMemberPromise = payload.organizationId + ? this.isAuthenticatedForOrganization(payload._id, payload.organizationId) + : Promise.resolve(true); + const [user, isMember] = await Promise.all([userPromise, isMemberPromise]); + + if (!user) throw new UnauthorizedException('User not found'); + if (payload.organizationId && !isMember) { + throw new UnauthorizedException( + `Not authorized for organization ${payload.organizationId}` + ); + } + + return user; + } + + public async validateSubscriber( + payload: ISubscriberJwt + ): Promise { + return await this.getSubscriber({ + _environmentId: payload.environmentId, + subscriberId: payload.subscriberId, + }); + } + + public async isRootEnvironment(payload: UserSessionData): Promise { + const environment = await this.environmentRepository.findOne({ + _id: payload.environmentId, + }); + if (!environment) throw new NotFoundException('Environment not found'); + + return !!environment._parentId; + } + + @Instrument() + @CachedEntity({ + builder: (command: { _id: string }) => + buildUserKey({ + _id: command._id, + }), + }) + private async getUser({ _id }: { _id: string }) { + return await this.userRepository.findById(_id); + } + + @CachedEntity({ + builder: (command: { subscriberId: string; _environmentId: string }) => + buildSubscriberKey({ + _environmentId: command._environmentId, + subscriberId: command.subscriberId, + }), + }) + private async getSubscriber({ + subscriberId, + _environmentId, + }: { + subscriberId: string; + _environmentId: string; + }): Promise { + return await this.subscriberRepository.findBySubscriberId( + _environmentId, + subscriberId + ); + } + + @CachedEntity({ + builder: ({ apiKey }: { apiKey: string }) => + buildAuthServiceKey({ + apiKey: apiKey, + }), + }) + private async getApiKeyUser({ apiKey }: { apiKey: string }): Promise<{ + environment?: EnvironmentEntity; + user?: UserEntity; + error?: string; + }> { + const hashedApiKey = createHash('sha256').update(apiKey).digest('hex'); + + const environment = await this.environmentRepository.findByApiKey({ + key: apiKey, + hash: hashedApiKey, + }); + + if (!environment) { + // Failed to find the environment for the provided API key. + return { error: 'API Key not found' }; + } + + let key = environment.apiKeys.find((i) => i.hash === hashedApiKey); + + if (!key) { + /* + * backward compatibility - delete after encrypt-api-keys-migration execution + * find by decrypted key if key not found, because of backward compatibility + * use-case: findByApiKey found by decrypted key, so we need to validate by decrypted key + */ + key = environment.apiKeys.find((i) => i.key === apiKey); + } + + if (!key) { + return { error: 'API Key not found' }; + } + + const user = await this.userRepository.findById(key._userId); + if (!user) { + return { error: 'User not found' }; + } + + return { environment, user }; + } +} diff --git a/libs/application-generic/src/services/auth/community.user.auth.guard.ts b/libs/application-generic/src/services/auth/community.user.auth.guard.ts new file mode 100644 index 00000000000..b57f95b0a1f --- /dev/null +++ b/libs/application-generic/src/services/auth/community.user.auth.guard.ts @@ -0,0 +1,83 @@ +import { + ExecutionContext, + Injectable, + UnauthorizedException, +} from '@nestjs/common'; +import { AuthGuard, IAuthModuleOptions } from '@nestjs/passport'; +import { Reflector } from '@nestjs/core'; +import { + ApiAuthSchemeEnum, + IJwtClaims, + PassportStrategyEnum, + HandledUser, + NONE_AUTH_SCHEME, +} from '@novu/shared'; + +@Injectable() +export class CommunityUserAuthGuard extends AuthGuard([ + PassportStrategyEnum.JWT, + PassportStrategyEnum.HEADER_API_KEY, +]) { + constructor(private readonly reflector: Reflector) { + super(); + } + + getAuthenticateOptions(context: ExecutionContext): IAuthModuleOptions { + const request = context.switchToHttp().getRequest(); + const authorizationHeader = request.headers.authorization; + + const authScheme = authorizationHeader?.split(' ')[0] || NONE_AUTH_SCHEME; + request.authScheme = authScheme; + + switch (authScheme) { + case ApiAuthSchemeEnum.BEARER: + return { + session: false, + defaultStrategy: PassportStrategyEnum.JWT, + }; + case ApiAuthSchemeEnum.API_KEY: + const apiEnabled = this.reflector.get( + 'external_api_accessible', + context.getHandler() + ); + if (!apiEnabled) + throw new UnauthorizedException('API endpoint not available'); + + return { + session: false, + defaultStrategy: PassportStrategyEnum.HEADER_API_KEY, + }; + case NONE_AUTH_SCHEME: + throw new UnauthorizedException('Missing authorization header'); + default: + throw new UnauthorizedException( + `Invalid authentication scheme: "${authScheme}"` + ); + } + } + + handleRequest( + err: any, + user: IJwtClaims | false, + info: any, + context: ExecutionContext, + status?: any + ): TUser { + let handledUser: HandledUser; + if (typeof user === 'object') { + /** + * This helps with sentry and other tools that need to know who the user is based on `id` property. + */ + handledUser = { + ...user, + id: user._id, + username: (user.firstName || '').trim(), + domain: user.email?.split('@')[1], + }; + } else { + handledUser = user; + } + + return super.handleRequest(err, handledUser, info, context, status); + } +} diff --git a/libs/application-generic/src/services/auth/index.ts b/libs/application-generic/src/services/auth/index.ts index 9982ba8ea9a..f338fa28e40 100644 --- a/libs/application-generic/src/services/auth/index.ts +++ b/libs/application-generic/src/services/auth/index.ts @@ -1,3 +1,6 @@ export * from './auth.service'; +export * from './community.auth.service'; +export * from './community.user.auth.guard'; export * from './user.auth.guard'; export * from './shared'; +export * from './auth.service.interface'; diff --git a/libs/application-generic/src/services/auth/user.auth.guard.ts b/libs/application-generic/src/services/auth/user.auth.guard.ts index 65cd1ea12f3..fc12cb9970c 100644 --- a/libs/application-generic/src/services/auth/user.auth.guard.ts +++ b/libs/application-generic/src/services/auth/user.auth.guard.ts @@ -1,75 +1,22 @@ -import { - ExecutionContext, - Injectable, - UnauthorizedException, -} from '@nestjs/common'; -import { AuthGuard, IAuthModuleOptions } from '@nestjs/passport'; -import { Reflector } from '@nestjs/core'; -import { - ApiAuthSchemeEnum, - PassportStrategyEnum, - UserSessionData, -} from '@novu/shared'; -import { Instrument } from '../../instrumentation'; +import { Injectable, ExecutionContext, Inject } from '@nestjs/common'; +import { IAuthGuard, IAuthModuleOptions } from '@nestjs/passport'; import { Observable } from 'rxjs'; - -type SentryUser = { - id: string; - username: string; - domain: string; -}; -type HandledUser = (UserSessionData & SentryUser) | false; - -const NONE_AUTH_SCHEME = 'None'; +import { Instrument } from '../../instrumentation'; +import { UserSessionData } from '@novu/shared'; @Injectable() -export class UserAuthGuard extends AuthGuard([ - PassportStrategyEnum.JWT, - PassportStrategyEnum.HEADER_API_KEY, -]) { - constructor(private readonly reflector: Reflector) { - super(); - } +export class UserAuthGuard { + constructor(@Inject('USER_AUTH_GUARD') private authGuard: IAuthGuard) {} @Instrument() canActivate( context: ExecutionContext ): boolean | Promise | Observable { - return super.canActivate(context); + return this.authGuard.canActivate(context); } getAuthenticateOptions(context: ExecutionContext): IAuthModuleOptions { - const request = context.switchToHttp().getRequest(); - const authorizationHeader = request.headers.authorization; - - const authScheme = authorizationHeader?.split(' ')[0] || NONE_AUTH_SCHEME; - request.authScheme = authScheme; - - switch (authScheme) { - case ApiAuthSchemeEnum.BEARER: - return { - session: false, - defaultStrategy: PassportStrategyEnum.JWT, - }; - case ApiAuthSchemeEnum.API_KEY: - const apiEnabled = this.reflector.get( - 'external_api_accessible', - context.getHandler() - ); - if (!apiEnabled) - throw new UnauthorizedException('API endpoint not available'); - - return { - session: false, - defaultStrategy: PassportStrategyEnum.HEADER_API_KEY, - }; - case NONE_AUTH_SCHEME: - throw new UnauthorizedException('Missing authorization header'); - default: - throw new UnauthorizedException( - `Invalid authentication scheme: "${authScheme}"` - ); - } + return this.authGuard.getAuthenticateOptions(context); } handleRequest( @@ -79,21 +26,6 @@ export class UserAuthGuard extends AuthGuard([ context: ExecutionContext, status?: any ): TUser { - let handledUser: HandledUser; - if (typeof user === 'object') { - /** - * This helps with sentry and other tools that need to know who the user is based on `id` property. - */ - handledUser = { - ...user, - id: user._id, - username: (user.firstName || '').trim(), - domain: user.email?.split('@')[1], - }; - } else { - handledUser = user; - } - - return super.handleRequest(err, handledUser, info, context, status); + return this.authGuard.handleRequest(err, user, info, context, status); } } diff --git a/libs/application-generic/src/usecases/switch-organization/switch-organization.usecase.ts b/libs/application-generic/src/usecases/switch-organization/switch-organization.usecase.ts index e6108ffbc75..b6d39e92361 100644 --- a/libs/application-generic/src/usecases/switch-organization/switch-organization.usecase.ts +++ b/libs/application-generic/src/usecases/switch-organization/switch-organization.usecase.ts @@ -6,7 +6,6 @@ import { } from '@nestjs/common'; import { MemberRepository, - OrganizationRepository, UserRepository, EnvironmentRepository, } from '@novu/dal'; @@ -17,7 +16,6 @@ import { ApiException } from '../../utils/exceptions'; @Injectable() export class SwitchOrganization { constructor( - private organizationRepository: OrganizationRepository, private userRepository: UserRepository, private memberRepository: MemberRepository, private environmentRepository: EnvironmentRepository, diff --git a/libs/application-generic/src/utils/inject-repositories.ts b/libs/application-generic/src/utils/inject-repositories.ts new file mode 100644 index 00000000000..18c1c960363 --- /dev/null +++ b/libs/application-generic/src/utils/inject-repositories.ts @@ -0,0 +1,228 @@ +import { Reflector } from '@nestjs/core'; +import { JwtService } from '@nestjs/jwt'; +import { + CommunityUserRepository, + CommunityMemberRepository, + CommunityOrganizationRepository, + EnvironmentRepository, + SubscriberRepository, + UserRepository, + MemberRepository, + OrganizationRepository, +} from '@novu/dal'; +import { isClerkEnabled } from '@novu/shared'; +import { + AnalyticsService, + CommunityAuthService, + CommunityUserAuthGuard, +} from '../services'; +import { CreateUser, SwitchOrganization, SwitchEnvironment } from '../usecases'; + +class PlatformException extends Error {} + +function injectClerkClientMock() { + if (process.env.NODE_ENV === 'test') { + const clerkClientMock = require('@novu/ee-auth').ClerkClientMock; + + return new clerkClientMock(); + } +} + +export function injectRepositories( + { repositoriesOnly }: { repositoriesOnly?: boolean } = { + repositoriesOnly: true, + } +) { + if (!isClerkEnabled()) { + const userRepositoryProvider = { + provide: 'USER_REPOSITORY', + useClass: CommunityUserRepository, + }; + + const memberRepositoryProvider = { + provide: 'MEMBER_REPOSITORY', + useClass: CommunityMemberRepository, + }; + + const organizationRepositoryProvider = { + provide: 'ORGANIZATION_REPOSITORY', + useClass: CommunityOrganizationRepository, + }; + + const authServiceProvider = { + provide: 'AUTH_SERVICE', + useFactory: ( + userRepository: UserRepository, + subscriberRepository: SubscriberRepository, + createUserUsecase: CreateUser, + jwtService: JwtService, + analyticsService: AnalyticsService, + organizationRepository: OrganizationRepository, + environmentRepository: EnvironmentRepository, + memberRepository: MemberRepository, + switchOrganizationUsecase: SwitchOrganization, + switchEnvironmentUsecase: SwitchEnvironment + ) => { + return new CommunityAuthService( + userRepository, + subscriberRepository, + createUserUsecase, + jwtService, + analyticsService, + organizationRepository, + environmentRepository, + memberRepository, + switchOrganizationUsecase, + switchEnvironmentUsecase + ); + }, + inject: [ + UserRepository, + SubscriberRepository, + CreateUser, + JwtService, + AnalyticsService, + OrganizationRepository, + EnvironmentRepository, + MemberRepository, + SwitchOrganization, + SwitchEnvironment, + ], + }; + + const userAuthGuardProvider = { + provide: 'USER_AUTH_GUARD', + useFactory: (reflector: Reflector) => { + return new CommunityUserAuthGuard(reflector); + }, + inject: [Reflector], + }; + + if (repositoriesOnly) { + return [ + userRepositoryProvider, + memberRepositoryProvider, + organizationRepositoryProvider, + ]; + } + + return [ + userRepositoryProvider, + memberRepositoryProvider, + organizationRepositoryProvider, + authServiceProvider, + userAuthGuardProvider, + ]; + } + + const eeUserRepositoryProvider = { + provide: 'USER_REPOSITORY', + useFactory: (userRepository: CommunityUserRepository) => { + const eeAuthPackage = require('@novu/ee-auth'); + if (!eeAuthPackage?.EEUserRepository) { + throw new PlatformException('EEUserRepository is not loaded'); + } + + return new eeAuthPackage.EEUserRepository( + userRepository, + injectClerkClientMock() + ); + }, + inject: [CommunityUserRepository], + }; + + const eeMemberRepositoryProvider = { + provide: 'MEMBER_REPOSITORY', + useFactory: (organizationRepository: CommunityOrganizationRepository) => { + const eeAuthPackage = require('@novu/ee-auth'); + if (!eeAuthPackage?.EEMemberRepository) { + throw new PlatformException('EEMemberRepository is not loaded'); + } + + return new eeAuthPackage.EEMemberRepository( + organizationRepository, + injectClerkClientMock() + ); + }, + inject: [CommunityOrganizationRepository], + }; + + const eeOrganizationRepositoryProvider = { + provide: 'ORGANIZATION_REPOSITORY', + useFactory: (organizationRepository: CommunityOrganizationRepository) => { + const eeAuthPackage = require('@novu/ee-auth'); + if (!eeAuthPackage?.EEOrganizationRepository) { + throw new PlatformException('EEOrganizationRepository is not loaded'); + } + + return new eeAuthPackage.EEOrganizationRepository( + organizationRepository, + injectClerkClientMock() + ); + }, + inject: [CommunityOrganizationRepository], + }; + + const eeAuthServiceProvider = { + provide: 'AUTH_SERVICE', + useFactory: ( + userRepository: UserRepository, + environmentRepository: EnvironmentRepository, + subscriberRepository: SubscriberRepository, + jwtService: JwtService + ) => { + const eeAuthPackage = require('@novu/ee-auth'); + if (!eeAuthPackage?.EEAuthService) { + throw new PlatformException('EEAuthService is not loaded'); + } + + return new eeAuthPackage.EEAuthService( + userRepository, + environmentRepository, + subscriberRepository, + jwtService + ); + }, + inject: [ + UserRepository, + EnvironmentRepository, + SubscriberRepository, + JwtService, + ], + }; + + const eeUserAuthGuard = { + provide: 'USER_AUTH_GUARD', + useFactory: (reflector: Reflector) => { + const eeAuthPackage = require('@novu/ee-auth'); + if (!eeAuthPackage?.EEUserAuthGuard) { + throw new PlatformException('EEUserAuthGuard is not loaded'); + } + + return new eeAuthPackage.EEUserAuthGuard(reflector); + }, + inject: [Reflector], + }; + + if (repositoriesOnly) { + return [ + eeUserRepositoryProvider, + CommunityUserRepository, + eeMemberRepositoryProvider, + CommunityMemberRepository, + eeOrganizationRepositoryProvider, + CommunityOrganizationRepository, + ]; + } + + return [ + eeUserRepositoryProvider, + CommunityUserRepository, + eeMemberRepositoryProvider, + CommunityMemberRepository, + eeOrganizationRepositoryProvider, + CommunityOrganizationRepository, + eeAuthServiceProvider, + eeUserAuthGuard, + ]; +} diff --git a/libs/dal/package.json b/libs/dal/package.json index d1f7973686f..d6004873826 100644 --- a/libs/dal/package.json +++ b/libs/dal/package.json @@ -20,6 +20,9 @@ "license": "ISC", "main": "dist/index.js", "types": "dist/index.d.ts", + "peerDependencies": { + "@nestjs/common": "10.2.2" + }, "dependencies": { "@aws-sdk/client-s3": "^3.382.0", "@aws-sdk/s3-request-presigner": "^3.382.0", diff --git a/libs/dal/src/repositories/index.ts b/libs/dal/src/repositories/index.ts new file mode 100644 index 00000000000..fab907a385d --- /dev/null +++ b/libs/dal/src/repositories/index.ts @@ -0,0 +1 @@ +export * from './base-repository'; diff --git a/libs/dal/src/repositories/member/community.member.repository.ts b/libs/dal/src/repositories/member/community.member.repository.ts new file mode 100644 index 00000000000..79536c0f204 --- /dev/null +++ b/libs/dal/src/repositories/member/community.member.repository.ts @@ -0,0 +1,202 @@ +import { MemberRoleEnum, MemberStatusEnum } from '@novu/shared'; +import { MemberEntity, MemberDBModel } from './member.entity'; +import { BaseRepository } from '../base-repository'; +import { Member } from './member.schema'; +import type { EnforceOrgId } from '../../types/enforce'; +import { IMemberRepository } from './member-repository.interface'; +import { IAddMemberData } from './member.repository'; +import { FilterQuery } from 'mongoose'; + +type MemberQuery = FilterQuery & EnforceOrgId; + +export class CommunityMemberRepository + extends BaseRepository + implements IMemberRepository +{ + constructor() { + super(Member, MemberEntity); + } + + async removeMemberById( + organizationId: string, + memberId: string + ): Promise<{ + /** Indicates whether this write result was acknowledged. If not, then all other members of this result will be undefined. */ + acknowledged: boolean; + /** The number of documents that were deleted */ + deletedCount: number; + }> { + return this.MongooseModel.deleteOne({ + _id: memberId, + _organizationId: organizationId, + }); + } + + async updateMemberRoles(organizationId: string, memberId: string, roles: MemberRoleEnum[]) { + return this.update( + { + _id: memberId, + _organizationId: organizationId, + }, + { + roles, + } + ); + } + + async getOrganizationMembers(organizationId: string) { + const requestQuery: MemberQuery = { + _organizationId: organizationId, + }; + + const members = await this.MongooseModel.find(requestQuery).populate( + '_userId', + 'firstName lastName email _id profilePicture createdAt' + ); + if (!members) return []; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const membersEntity: any = this.mapEntities(members); + + return [ + ...membersEntity.map((member) => { + return { + ...member, + _userId: member._userId ? member._userId._id : null, + user: member._userId, + }; + }), + ]; + } + + async getOrganizationAdminAccount(organizationId: string) { + const requestQuery: MemberQuery = { + _organizationId: organizationId, + roles: MemberRoleEnum.ADMIN, + }; + + const member = await this.MongooseModel.findOne(requestQuery); + + return this.mapEntity(member); + } + + async getOrganizationAdmins(organizationId: string) { + const requestQuery: MemberQuery = { + _organizationId: organizationId, + }; + + const members = await this.MongooseModel.find(requestQuery).populate('_userId', 'firstName lastName email _id'); + if (!members) return []; + + const membersEntity = this.mapEntities(members); + + return [ + ...membersEntity + .filter((i) => i.roles.includes(MemberRoleEnum.ADMIN)) + .map((member) => { + return { + ...member, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + _userId: member._userId ? (member._userId as any)._id : null, + user: member._userId, + }; + }), + ]; + } + + async findUserActiveMembers(userId: string): Promise { + // exception casting - due to the login logic in generateUserToken + const requestQuery = { + _userId: userId, + memberStatus: MemberStatusEnum.ACTIVE, + } as unknown as MemberQuery; + + return await this.find(requestQuery); + } + + async convertInvitedUserToMember( + organizationId: string, + token: string, + data: { + memberStatus: MemberStatusEnum; + _userId: string; + answerDate: Date; + } + ) { + await this.update( + { + _organizationId: organizationId, + 'invite.token': token, + }, + { + memberStatus: data.memberStatus, + _userId: data._userId, + 'invite.answerDate': data.answerDate, + } + ); + } + + async findByInviteToken(token: string) { + const requestQuery = { + 'invite.token': token, + } as unknown as MemberQuery; + + return await this.findOne(requestQuery); + } + + async findInviteeByEmail(organizationId: string, email: string): Promise { + const foundMember = await this.findOne({ + _organizationId: organizationId, + 'invite.email': email, + }); + + if (!foundMember) return null; + + return foundMember; + } + + async addMember(organizationId: string, member: IAddMemberData): Promise { + await this.create({ + _userId: member._userId, + roles: member.roles, + invite: member.invite, + memberStatus: member.memberStatus, + _organizationId: organizationId, + }); + } + + async isMemberOfOrganization(organizationId: string, userId: string): Promise { + return !!(await this.findOne( + { + _organizationId: organizationId, + _userId: userId, + }, + '_id', + { + readPreference: 'secondaryPreferred', + } + )); + } + + async findMemberByUserId(organizationId: string, userId: string): Promise { + const member = await this.findOne({ + _organizationId: organizationId, + _userId: userId, + }); + + if (!member) return null; + + return this.mapEntity(member) as MemberEntity; + } + + async findMemberById(organizationId: string, memberId: string): Promise { + const member = await this.findOne({ + _organizationId: organizationId, + _id: memberId, + }); + + if (!member) return null; + + return this.mapEntity(member) as MemberEntity; + } +} diff --git a/libs/dal/src/repositories/member/index.ts b/libs/dal/src/repositories/member/index.ts index 35f4ff1b98d..d48eb84b462 100644 --- a/libs/dal/src/repositories/member/index.ts +++ b/libs/dal/src/repositories/member/index.ts @@ -1,2 +1,5 @@ export * from './member.repository'; +export * from './community.member.repository'; export * from './member.entity'; +export * from './member-repository.interface'; +export * from './member.schema'; diff --git a/libs/dal/src/repositories/member/member-repository.interface.ts b/libs/dal/src/repositories/member/member-repository.interface.ts new file mode 100644 index 00000000000..c795c0eb3f9 --- /dev/null +++ b/libs/dal/src/repositories/member/member-repository.interface.ts @@ -0,0 +1,73 @@ +import { MemberRoleEnum, MemberStatusEnum, IMemberInvite } from '@novu/shared'; +import { Types } from 'mongoose'; +import { MemberEntity } from './member.entity'; +import { IAddMemberData } from './member.repository'; + +export interface IMemberRepository extends IMemberRepositoryMongo { + removeMemberById( + organizationId: string, + memberId: string + ): Promise<{ + acknowledged: boolean; + deletedCount: number; + }>; + updateMemberRoles( + organizationId: string, + memberId: string, + roles: MemberRoleEnum[] + ): Promise<{ + matched: number; + modified: number; + }>; + getOrganizationMembers(organizationId: string): Promise; + getOrganizationAdminAccount(organizationId: string): Promise; + getOrganizationAdmins(organizationId: string): Promise< + { + _userId: any; + user: string; + _id: string; + roles: MemberRoleEnum[]; + invite?: IMemberInvite | undefined; + memberStatus: MemberStatusEnum; + _organizationId: string; + }[] + >; + findUserActiveMembers(userId: string): Promise; + convertInvitedUserToMember( + organizationId: string, + token: string, + data: { + memberStatus: MemberStatusEnum; + _userId: string; + answerDate: Date; + } + ): Promise; + findByInviteToken(token: string): Promise; + findInviteeByEmail(organizationId: string, email: string): Promise; + addMember(organizationId: string, member: IAddMemberData): Promise; + isMemberOfOrganization(organizationId: string, userId: string): Promise; + findMemberByUserId(organizationId: string, userId: string): Promise; + findMemberById(organizationId: string, memberId: string): Promise; +} + +/** + * MongoDB specific methods from base-repository.ts to achieve + * common interface for EE and Community repositories + */ +export interface IMemberRepositoryMongo { + create(data: any, options?: any): Promise; + update(query: any, body: any): Promise<{ matched: number; modified: number }>; + delete(query: any): Promise<{ acknowledged: boolean; deletedCount: number }>; + count(query: any, limit?: number): Promise; + aggregate(query: any[], options?: { readPreference?: 'secondaryPreferred' | 'primary' }): Promise; + findOne(query: any, select?: any, options?: any): Promise; + find(query: any, select?: any, options?: any): Promise; + findBatch(query: any, select?: string, options?: any, batchSize?: number): AsyncGenerator; + insertMany( + data: any, + ordered: boolean + ): Promise<{ acknowledged: boolean; insertedCount: number; insertedIds: Types.ObjectId[] }>; + updateOne(query: any, body: any): Promise<{ matched: number; modified: number }>; + upsertMany(data: any): Promise; + bulkWrite(bulkOperations: any, ordered: boolean): Promise; +} diff --git a/libs/dal/src/repositories/member/member.repository.ts b/libs/dal/src/repositories/member/member.repository.ts index 854954652dc..01ae9d779f3 100644 --- a/libs/dal/src/repositories/member/member.repository.ts +++ b/libs/dal/src/repositories/member/member.repository.ts @@ -1,10 +1,7 @@ -import { FilterQuery } from 'mongoose'; -import { IMemberInvite, MemberRoleEnum, MemberStatusEnum } from '@novu/shared'; - -import { MemberEntity, MemberDBModel } from './member.entity'; -import { BaseRepository } from '../base-repository'; -import { Member } from './member.schema'; -import type { EnforceOrgId } from '../../types/enforce'; +import { Inject } from '@nestjs/common'; +import { MemberRoleEnum, IMemberInvite, MemberStatusEnum } from '@novu/shared'; +import { IMemberRepository } from './member-repository.interface'; +import { MemberEntity } from './member.entity'; export interface IAddMemberData { _userId?: string; @@ -13,193 +10,129 @@ export interface IAddMemberData { memberStatus: MemberStatusEnum; } -type MemberQuery = FilterQuery & EnforceOrgId; +export class MemberRepository implements IMemberRepository { + constructor(@Inject('MEMBER_REPOSITORY') private memberRepository: IMemberRepository) {} -export class MemberRepository extends BaseRepository { - constructor() { - super(Member, MemberEntity); + removeMemberById(organizationId: string, memberId: string): Promise<{ acknowledged: boolean; deletedCount: number }> { + return this.memberRepository.removeMemberById(organizationId, memberId); } - async removeMemberById( + updateMemberRoles( organizationId: string, - memberId: string - ): Promise<{ - /** Indicates whether this write result was acknowledged. If not, then all other members of this result will be undefined. */ - acknowledged: boolean; - /** The number of documents that were deleted */ - deletedCount: number; - }> { - return this.MongooseModel.deleteOne({ - _id: memberId, - _organizationId: organizationId, - }); - } - - async updateMemberRoles(organizationId: string, memberId: string, roles: MemberRoleEnum[]) { - return this.update( - { - _id: memberId, - _organizationId: organizationId, - }, - { - roles, - } - ); - } - - async getOrganizationMembers(organizationId: string) { - const requestQuery: MemberQuery = { - _organizationId: organizationId, - }; - - const members = await this.MongooseModel.find(requestQuery).populate( - '_userId', - 'firstName lastName email _id profilePicture createdAt' - ); - if (!members) return []; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const membersEntity: any = this.mapEntities(members); - - return [ - ...membersEntity.map((member) => { - return { - ...member, - _userId: member._userId ? member._userId._id : null, - user: member._userId, - }; - }), - ]; - } - - async getOrganizationAdminAccount(organizationId: string) { - const requestQuery: MemberQuery = { - _organizationId: organizationId, - roles: MemberRoleEnum.ADMIN, - }; - - const member = await this.MongooseModel.findOne(requestQuery); - - return this.mapEntity(member); - } - - async getOrganizationAdmins(organizationId: string) { - const requestQuery: MemberQuery = { - _organizationId: organizationId, - }; - - const members = await this.MongooseModel.find(requestQuery).populate('_userId', 'firstName lastName email _id'); - if (!members) return []; - - const membersEntity = this.mapEntities(members); - - return [ - ...membersEntity - .filter((i) => i.roles.includes(MemberRoleEnum.ADMIN)) - .map((member) => { - return { - ...member, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - _userId: member._userId ? (member._userId as any)._id : null, - user: member._userId, - }; - }), - ]; - } - - async findUserActiveMembers(userId: string): Promise { - // exception casting - due to the login logic in generateUserToken - const requestQuery = { - _userId: userId, - memberStatus: MemberStatusEnum.ACTIVE, - } as unknown as MemberQuery; - - return await this.find(requestQuery); - } - - async convertInvitedUserToMember( + memberId: string, + roles: MemberRoleEnum[] + ): Promise<{ matched: number; modified: number }> { + return this.memberRepository.updateMemberRoles(organizationId, memberId, roles); + } + + getOrganizationMembers(organizationId: string): Promise { + return this.memberRepository.getOrganizationMembers(organizationId); + } + + getOrganizationAdminAccount(organizationId: string): Promise { + return this.memberRepository.getOrganizationAdminAccount(organizationId); + } + + getOrganizationAdmins(organizationId: string): Promise< + { + _userId: any; + user: string; + _id: string; + roles: MemberRoleEnum[]; + invite?: IMemberInvite | undefined; + memberStatus: MemberStatusEnum; + _organizationId: string; + }[] + > { + return this.memberRepository.getOrganizationAdmins(organizationId); + } + + findUserActiveMembers(userId: string): Promise { + return this.memberRepository.findUserActiveMembers(userId); + } + + convertInvitedUserToMember( organizationId: string, token: string, - data: { - memberStatus: MemberStatusEnum; - _userId: string; - answerDate: Date; - } - ) { - await this.update( - { - _organizationId: organizationId, - 'invite.token': token, - }, - { - memberStatus: data.memberStatus, - _userId: data._userId, - 'invite.answerDate': data.answerDate, - } - ); + data: { memberStatus: MemberStatusEnum; _userId: string; answerDate: Date } + ): Promise { + return this.memberRepository.convertInvitedUserToMember(organizationId, token, data); + } + + findByInviteToken(token: string): Promise { + return this.memberRepository.findByInviteToken(token); } - async findByInviteToken(token: string) { - const requestQuery = { - 'invite.token': token, - } as unknown as MemberQuery; + findInviteeByEmail(organizationId: string, email: string): Promise { + return this.memberRepository.findInviteeByEmail(organizationId, email); + } + + addMember(organizationId: string, member: IAddMemberData): Promise { + return this.memberRepository.addMember(organizationId, member); + } - return await this.findOne(requestQuery); + isMemberOfOrganization(organizationId: string, userId: string): Promise { + return this.memberRepository.isMemberOfOrganization(organizationId, userId); } - async findInviteeByEmail(organizationId: string, email: string): Promise { - const foundMember = await this.findOne({ - _organizationId: organizationId, - 'invite.email': email, - }); + findMemberByUserId(organizationId: string, userId: string): Promise { + return this.memberRepository.findMemberByUserId(organizationId, userId); + } - if (!foundMember) return null; + findMemberById(organizationId: string, memberId: string): Promise { + return this.memberRepository.findMemberById(organizationId, memberId); + } - return foundMember; + create(data: any, options?: any): Promise { + return this.memberRepository.create(data, options); } - async addMember(organizationId: string, member: IAddMemberData): Promise { - await this.create({ - _userId: member._userId, - roles: member.roles, - invite: member.invite, - memberStatus: member.memberStatus, - _organizationId: organizationId, - }); + update(query: any, body: any): Promise<{ matched: number; modified: number }> { + return this.memberRepository.update(query, body); } - async isMemberOfOrganization(organizationId: string, userId: string): Promise { - return !!(await this.findOne( - { - _organizationId: organizationId, - _userId: userId, - }, - '_id', - { - readPreference: 'secondaryPreferred', - } - )); + delete(query: any): Promise<{ acknowledged: boolean; deletedCount: number }> { + return this.memberRepository.delete(query); } - async findMemberByUserId(organizationId: string, userId: string): Promise { - const member = await this.findOne({ - _organizationId: organizationId, - _userId: userId, - }); + count(query: any, limit?: number): Promise { + return this.memberRepository.count(query, limit); + } - if (!member) return null; + aggregate(query: any[], options?: { readPreference?: 'secondaryPreferred' | 'primary' }): Promise { + return this.memberRepository.aggregate(query, options); + } - return this.mapEntity(member) as MemberEntity; + findOne(query: any, select?: any, options?: any): Promise { + return this.memberRepository.findOne(query, select, options); } - async findMemberById(organizationId: string, memberId: string): Promise { - const member = await this.findOne({ - _organizationId: organizationId, - _id: memberId, - }); + find(query: any, select?: any, options?: any): Promise { + return this.memberRepository.find(query, select, options); + } - if (!member) return null; + async *findBatch( + query: any, + select?: string | undefined, + options?: any, + batchSize?: number | undefined + ): AsyncGenerator { + return this.memberRepository.findBatch(query, select, options, batchSize); + } + + insertMany(data: any, ordered: boolean): Promise<{ acknowledged: boolean; insertedCount: number; insertedIds: any }> { + return this.memberRepository.insertMany(data, ordered); + } + + updateOne(query: any, body: any): Promise<{ matched: number; modified: number }> { + return this.memberRepository.updateOne(query, body); + } + + upsertMany(data: any): Promise { + return this.memberRepository.upsertMany(data); + } - return this.mapEntity(member) as MemberEntity; + bulkWrite(bulkOperations: any, ordered: boolean): Promise { + return this.memberRepository.bulkWrite(bulkOperations, ordered); } } diff --git a/libs/dal/src/repositories/organization/community.organization.repository.ts b/libs/dal/src/repositories/organization/community.organization.repository.ts new file mode 100644 index 00000000000..187f64cc13b --- /dev/null +++ b/libs/dal/src/repositories/organization/community.organization.repository.ts @@ -0,0 +1,138 @@ +import { IPartnerConfiguration, OrganizationDBModel, OrganizationEntity } from './organization.entity'; +import { BaseRepository } from '../base-repository'; +import { Organization } from './organization.schema'; +import { CommunityMemberRepository } from '../member'; +import { ApiServiceLevelEnum } from '@novu/shared'; +import { IOrganizationRepository } from './organization-repository.interface'; + +export class CommunityOrganizationRepository + extends BaseRepository + implements IOrganizationRepository +{ + private memberRepository = new CommunityMemberRepository(); + + constructor() { + super(Organization, OrganizationEntity); + } + + async findById(id: string, select?: string): Promise { + const data = await this.MongooseModel.findById(id, select).read('secondaryPreferred'); + if (!data) return null; + + return this.mapEntity(data.toObject()); + } + + async findUserActiveOrganizations(userId: string): Promise { + const organizationIds = await this.getUsersMembersOrganizationIds(userId); + + return await this.find({ + _id: { $in: organizationIds }, + }); + } + + private async getUsersMembersOrganizationIds(userId: string): Promise { + const members = await this.memberRepository.findUserActiveMembers(userId); + + return members.map((member) => member._organizationId); + } + + async updateBrandingDetails(organizationId: string, branding: { color: string; logo: string }) { + return this.update( + { + _id: organizationId, + }, + { + $set: { + branding, + }, + } + ); + } + + async renameOrganization(organizationId: string, payload: { name: string }) { + return this.update( + { + _id: organizationId, + }, + { + $set: { + name: payload.name, + }, + } + ); + } + + async updateServiceLevel(organizationId: string, apiServiceLevel: ApiServiceLevelEnum) { + return this.update( + { + _id: organizationId, + }, + { + $set: { + apiServiceLevel, + }, + } + ); + } + + async updateDefaultLocale( + organizationId: string, + defaultLocale: string + ): Promise<{ matched: number; modified: number }> { + return this.update( + { + _id: organizationId, + }, + { + $set: { + defaultLocale, + }, + } + ); + } + + async findPartnerConfigurationDetails(organizationId: string, userId: string, configurationId: string) { + const organizationIds = await this.getUsersMembersOrganizationIds(userId); + + return await this.find( + { + _id: { $in: organizationIds }, + 'partnerConfigurations.configurationId': configurationId, + }, + { 'partnerConfigurations.$': 1 } + ); + } + + async updatePartnerConfiguration(organizationId: string, userId: string, configuration: IPartnerConfiguration) { + const organizationIds = await this.getUsersMembersOrganizationIds(userId); + + return this.update( + { + _id: { $in: organizationIds }, + }, + { + $push: { + partnerConfigurations: configuration, + }, + } + ); + } + + async bulkUpdatePartnerConfiguration(userId: string, data: Record, configurationId: string) { + const organizationIds = await this.getUsersMembersOrganizationIds(userId); + const usedOrgIds = Object.keys(data); + const unusedOrgIds = organizationIds.filter((org) => !usedOrgIds.includes(org)); + const bulkWriteOps = organizationIds.map((orgId) => { + return { + updateOne: { + filter: { _id: orgId, 'partnerConfigurations.configurationId': configurationId }, + update: { + 'partnerConfigurations.$.projectIds': unusedOrgIds.includes(orgId) ? [] : data[orgId], + }, + }, + }; + }); + + return await this.bulkWrite(bulkWriteOps); + } +} diff --git a/libs/dal/src/repositories/organization/index.ts b/libs/dal/src/repositories/organization/index.ts index 0edf418f30a..0f47f6a2962 100644 --- a/libs/dal/src/repositories/organization/index.ts +++ b/libs/dal/src/repositories/organization/index.ts @@ -1,3 +1,6 @@ export * from './organization.repository'; +export * from './community.organization.repository'; export * from './organization.entity'; export * from './types'; +export * from './organization-repository.interface'; +export * from './organization.schema'; diff --git a/libs/dal/src/repositories/organization/organization-repository.interface.ts b/libs/dal/src/repositories/organization/organization-repository.interface.ts new file mode 100644 index 00000000000..e1522336cd0 --- /dev/null +++ b/libs/dal/src/repositories/organization/organization-repository.interface.ts @@ -0,0 +1,72 @@ +import { IPartnerConfiguration, OrganizationEntity } from './organization.entity'; +import { ApiServiceLevelEnum } from '@novu/shared'; +import { Types } from 'mongoose'; + +export interface IOrganizationRepository extends IOrganizationRepositoryMongo { + findById(id: string, select?: string): Promise; + findUserActiveOrganizations(userId: string): Promise; + updateBrandingDetails( + organizationId: string, + branding: { color: string; logo: string } + ): Promise<{ + matched: number; + modified: number; + }>; + renameOrganization( + organizationId: string, + payload: { name: string } + ): Promise<{ + matched: number; + modified: number; + }>; + updateServiceLevel( + organizationId: string, + apiServiceLevel: ApiServiceLevelEnum + ): Promise<{ + matched: number; + modified: number; + }>; + updateDefaultLocale( + organizationId: string, + defaultLocale: string + ): Promise<{ + matched: number; + modified: number; + }>; + findPartnerConfigurationDetails( + organizationId: string, + userId: string, + configurationId: string + ): Promise; + updatePartnerConfiguration( + organizationId: string, + userId: string, + configuration: IPartnerConfiguration + ): Promise<{ + matched: number; + modified: number; + }>; + bulkUpdatePartnerConfiguration(userId: string, data: Record, configurationId: string): Promise; +} + +/** + * MongoDB specific methods from base-repository.ts to achieve + * common interface for EE and Community repositories + */ +export interface IOrganizationRepositoryMongo { + create(data: any, options?: any): Promise; + update(query: any, body: any): Promise<{ matched: number; modified: number }>; + delete(query: any): Promise<{ acknowledged: boolean; deletedCount: number }>; + count(query: any, limit?: number): Promise; + aggregate(query: any[], options?: { readPreference?: 'secondaryPreferred' | 'primary' }): Promise; + findOne(query: any, select?: any, options?: any): Promise; + find(query: any, select?: any, options?: any): Promise; + findBatch(query: any, select?: string, options?: any, batchSize?: number): AsyncGenerator; + insertMany( + data: any, + ordered: boolean + ): Promise<{ acknowledged: boolean; insertedCount: number; insertedIds: Types.ObjectId[] }>; + updateOne(query: any, body: any): Promise<{ matched: number; modified: number }>; + upsertMany(data: any): Promise; + bulkWrite(bulkOperations: any, ordered: boolean): Promise; +} diff --git a/libs/dal/src/repositories/organization/organization.entity.ts b/libs/dal/src/repositories/organization/organization.entity.ts index d08d3b3860f..b35438668f3 100644 --- a/libs/dal/src/repositories/organization/organization.entity.ts +++ b/libs/dal/src/repositories/organization/organization.entity.ts @@ -10,14 +10,7 @@ export class OrganizationEntity implements IOrganizationEntity { // TODO: NV-3067 - Remove optional once all organizations have a service level apiServiceLevel?: ApiServiceLevelEnum; - branding?: { - fontFamily?: string; - fontColor?: string; - contentBackground?: string; - logo: string; - color: string; - direction?: 'ltr' | 'rtl'; - }; + branding?: Branding; partnerConfigurations?: IPartnerConfiguration[]; @@ -34,8 +27,19 @@ export class OrganizationEntity implements IOrganizationEntity { updatedAt: string; externalId?: string; + + createdBy?: string; } +export type Branding = { + fontFamily?: string; + fontColor?: string; + contentBackground?: string; + logo: string; + color: string; + direction?: 'ltr' | 'rtl'; +}; + export type OrganizationDBModel = OrganizationEntity; export interface IPartnerConfiguration { diff --git a/libs/dal/src/repositories/organization/organization.repository.ts b/libs/dal/src/repositories/organization/organization.repository.ts index 1c5392590f1..126567b4b67 100644 --- a/libs/dal/src/repositories/organization/organization.repository.ts +++ b/libs/dal/src/repositories/organization/organization.repository.ts @@ -1,118 +1,97 @@ -import { IPartnerConfiguration, OrganizationDBModel, OrganizationEntity } from './organization.entity'; -import { BaseRepository } from '../base-repository'; -import { Organization } from './organization.schema'; -import { MemberRepository } from '../member'; +import { IPartnerConfiguration, OrganizationEntity } from './organization.entity'; import { ApiServiceLevelEnum } from '@novu/shared'; +import { IOrganizationRepository } from './organization-repository.interface'; +import { Inject } from '@nestjs/common'; -export class OrganizationRepository extends BaseRepository { - private memberRepository = new MemberRepository(); - - constructor() { - super(Organization, OrganizationEntity); - } - - async findById(id: string, select?: string): Promise { - const data = await this.MongooseModel.findById(id, select).read('secondaryPreferred'); - if (!data) return null; - - return this.mapEntity(data.toObject()); - } - - async findUserActiveOrganizations(userId: string): Promise { - const organizationIds = await this.getUsersMembersOrganizationIds(userId); - - return await this.find({ - _id: { $in: organizationIds }, - }); - } - - private async getUsersMembersOrganizationIds(userId: string): Promise { - const members = await this.memberRepository.findUserActiveMembers(userId); - - return members.map((member) => member._organizationId); - } - - async updateBrandingDetails(organizationId: string, branding: { color: string; logo: string }) { - return this.update( - { - _id: organizationId, - }, - { - $set: { - branding, - }, - } - ); - } - - async renameOrganization(organizationId: string, payload: { name: string }) { - return this.update( - { - _id: organizationId, - }, - { - $set: { - name: payload.name, - }, - } - ); - } - - async updateServiceLevel(organizationId: string, apiServiceLevel: ApiServiceLevelEnum) { - return this.update( - { - _id: organizationId, - }, - { - $set: { - apiServiceLevel, - }, - } - ); - } - - async findPartnerConfigurationDetails(organizationId: string, userId: string, configurationId: string) { - const organizationIds = await this.getUsersMembersOrganizationIds(userId); - - return await this.find( - { - _id: { $in: organizationIds }, - 'partnerConfigurations.configurationId': configurationId, - }, - { 'partnerConfigurations.$': 1 } - ); - } - - async updatePartnerConfiguration(organizationId: string, userId: string, configuration: IPartnerConfiguration) { - const organizationIds = await this.getUsersMembersOrganizationIds(userId); - - return this.update( - { - _id: { $in: organizationIds }, - }, - { - $push: { - partnerConfigurations: configuration, - }, - } - ); - } - - async bulkUpdatePartnerConfiguration(userId: string, data: Record, configurationId: string) { - const organizationIds = await this.getUsersMembersOrganizationIds(userId); - const usedOrgIds = Object.keys(data); - const unusedOrgIds = organizationIds.filter((org) => !usedOrgIds.includes(org)); - const bulkWriteOps = organizationIds.map((orgId) => { - return { - updateOne: { - filter: { _id: orgId, 'partnerConfigurations.configurationId': configurationId }, - update: { - 'partnerConfigurations.$.projectIds': unusedOrgIds.includes(orgId) ? [] : data[orgId], - }, - }, - }; - }); - - return await this.bulkWrite(bulkWriteOps); +export class OrganizationRepository implements IOrganizationRepository { + constructor(@Inject('ORGANIZATION_REPOSITORY') private organizationRepository: IOrganizationRepository) {} + + findById(id: string, select?: string): Promise { + return this.organizationRepository.findById(id, select); + } + + findUserActiveOrganizations(userId: string): Promise { + return this.organizationRepository.findUserActiveOrganizations(userId); + } + + updateBrandingDetails(organizationId: string, branding: { color: string; logo: string }) { + return this.organizationRepository.updateBrandingDetails(organizationId, branding); + } + + renameOrganization(organizationId: string, payload: { name: string }) { + return this.organizationRepository.renameOrganization(organizationId, payload); + } + + updateServiceLevel(organizationId: string, apiServiceLevel: ApiServiceLevelEnum) { + return this.organizationRepository.updateServiceLevel(organizationId, apiServiceLevel); + } + + updateDefaultLocale(organizationId: string, defaultLocale: string): Promise<{ matched: number; modified: number }> { + return this.organizationRepository.updateDefaultLocale(organizationId, defaultLocale); + } + + findPartnerConfigurationDetails(organizationId: string, userId: string, configurationId: string) { + return this.organizationRepository.findPartnerConfigurationDetails(organizationId, userId, configurationId); + } + + updatePartnerConfiguration(organizationId: string, userId: string, configuration: IPartnerConfiguration) { + return this.organizationRepository.updatePartnerConfiguration(organizationId, userId, configuration); + } + + bulkUpdatePartnerConfiguration(userId: string, data: Record, configurationId: string) { + return this.organizationRepository.bulkUpdatePartnerConfiguration(userId, data, configurationId); + } + + create(data: any, options?: any): Promise { + return this.organizationRepository.create(data, options); + } + + update(query: any, body: any): Promise<{ matched: number; modified: number }> { + return this.organizationRepository.update(query, body); + } + + delete(query: any): Promise<{ acknowledged: boolean; deletedCount: number }> { + return this.organizationRepository.delete(query); + } + + count(query: any, limit?: number): Promise { + return this.organizationRepository.count(query, limit); + } + + aggregate(query: any[], options?: { readPreference?: 'secondaryPreferred' | 'primary' }): Promise { + return this.organizationRepository.aggregate(query, options); + } + + findOne(query: any, select?: any, options?: any): Promise { + return this.organizationRepository.findOne(query, select, options); + } + + find(query: any, select?: any, options?: any): Promise { + return this.organizationRepository.find(query, select, options); + } + + async *findBatch( + query: any, + select?: string | undefined, + options?: any, + batchSize?: number | undefined + ): AsyncGenerator { + return this.organizationRepository.findBatch(query, select, options, batchSize); + } + + insertMany(data: any, ordered: boolean): Promise<{ acknowledged: boolean; insertedCount: number; insertedIds: any }> { + return this.organizationRepository.insertMany(data, ordered); + } + + updateOne(query: any, body: any): Promise<{ matched: number; modified: number }> { + return this.organizationRepository.updateOne(query, body); + } + + upsertMany(data: any): Promise { + return this.organizationRepository.upsertMany(data); + } + + bulkWrite(bulkOperations: any, ordered: boolean): Promise { + return this.organizationRepository.bulkWrite(bulkOperations, ordered); } } diff --git a/libs/dal/src/repositories/user/community.user.repository.ts b/libs/dal/src/repositories/user/community.user.repository.ts new file mode 100644 index 00000000000..56c7804250a --- /dev/null +++ b/libs/dal/src/repositories/user/community.user.repository.ts @@ -0,0 +1,52 @@ +import { createHash } from 'crypto'; +import { BaseRepository } from '../base-repository'; +import { IUserRepository } from './user-repository.interface'; +import { IUserResetTokenCount, UserEntity, UserDBModel } from './user.entity'; +import { User } from './user.schema'; + +export class CommunityUserRepository + extends BaseRepository + implements IUserRepository +{ + constructor() { + super(User, UserEntity); + } + + async findByEmail(email: string): Promise { + return this.findOne({ + email, + }); + } + + async findById(id: string, select?: string): Promise { + const data = await this.MongooseModel.findById(id, select); + if (!data) return null; + + return this.mapEntity(data.toObject()); + } + + private hashResetToken(token: string) { + return createHash('sha256').update(token).digest('hex'); + } + + async findUserByToken(token: string) { + return await this.findOne({ + resetToken: this.hashResetToken(token), + }); + } + + async updatePasswordResetToken(userId: string, token: string, resetTokenCount: IUserResetTokenCount) { + return await this.update( + { + _id: userId, + }, + { + $set: { + resetToken: this.hashResetToken(token), + resetTokenDate: new Date(), + resetTokenCount, + }, + } + ); + } +} diff --git a/libs/dal/src/repositories/user/index.ts b/libs/dal/src/repositories/user/index.ts index d29d22c1fe2..b9a1589ee97 100644 --- a/libs/dal/src/repositories/user/index.ts +++ b/libs/dal/src/repositories/user/index.ts @@ -1,3 +1,6 @@ export * from './types'; export * from './user.repository'; +export * from './community.user.repository'; export * from './user.entity'; +export * from './user.schema'; +export * from './user-repository.interface'; diff --git a/libs/dal/src/repositories/user/user-repository.interface.ts b/libs/dal/src/repositories/user/user-repository.interface.ts new file mode 100644 index 00000000000..60f5128d9b2 --- /dev/null +++ b/libs/dal/src/repositories/user/user-repository.interface.ts @@ -0,0 +1,35 @@ +import { Types } from 'mongoose'; +import { IUserResetTokenCount, UserEntity } from './user.entity'; + +export interface IUserRepository extends IUserRepositoryMongo { + findByEmail(email: string): Promise; + findById(id: string, select?: string): Promise; + findUserByToken(token: string): Promise; + updatePasswordResetToken( + userId: string, + token: string, + resetTokenCount: IUserResetTokenCount + ): Promise<{ matched: number; modified: number }>; +} + +/** + * MongoDB specific methods from base-repository.ts to achieve + * common interface for EE and Community repositories + */ +export interface IUserRepositoryMongo { + create(data: any, options?: any): Promise; + update(query: any, body: any): Promise<{ matched: number; modified: number }>; + delete(query: any): Promise<{ acknowledged: boolean; deletedCount: number }>; + count(query: any, limit?: number): Promise; + aggregate(query: any[], options?: { readPreference?: 'secondaryPreferred' | 'primary' }): Promise; + findOne(query: any, select?: any, options?: any): Promise; + find(query: any, select?: any, options?: any): Promise; + findBatch(query: any, select?: string, options?: any, batchSize?: number): AsyncGenerator; + insertMany( + data: any, + ordered: boolean + ): Promise<{ acknowledged: boolean; insertedCount: number; insertedIds: Types.ObjectId[] }>; + updateOne(query: any, body: any): Promise<{ matched: number; modified: number }>; + upsertMany(data: any): Promise; + bulkWrite(bulkOperations: any, ordered: boolean): Promise; +} diff --git a/libs/dal/src/repositories/user/user.entity.ts b/libs/dal/src/repositories/user/user.entity.ts index 157a6e73a61..61565aa56a9 100644 --- a/libs/dal/src/repositories/user/user.entity.ts +++ b/libs/dal/src/repositories/user/user.entity.ts @@ -17,7 +17,7 @@ export interface IUserResetTokenCount { reqInDay: number; } -export class UserEntity { +export class UserEntity implements IUserEntity { _id: UserId; resetToken?: string; @@ -54,6 +54,8 @@ export class UserEntity { jobTitle?: JobTitleEnum; + hasPassword: boolean; + externalId?: string; } diff --git a/libs/dal/src/repositories/user/user.repository.ts b/libs/dal/src/repositories/user/user.repository.ts index ba48734922f..869d8f7fe42 100644 --- a/libs/dal/src/repositories/user/user.repository.ts +++ b/libs/dal/src/repositories/user/user.repository.ts @@ -1,65 +1,87 @@ -import { AuthProviderEnum } from '@novu/shared'; -import { createHash } from 'crypto'; -import { BaseRepository } from '../base-repository'; -import { IUserResetTokenCount, UserEntity, UserDBModel } from './user.entity'; -import { User } from './user.schema'; +import { IUserRepository } from './user-repository.interface'; +import { UserEntity, IUserResetTokenCount } from './user.entity'; +import { Inject } from '@nestjs/common'; +import { Types } from 'mongoose'; -export class UserRepository extends BaseRepository { - constructor() { - super(User, UserEntity); - } +export class UserRepository implements IUserRepository { + constructor(@Inject('USER_REPOSITORY') private userRepository: IUserRepository) {} async findByEmail(email: string): Promise { - return this.findOne({ - email, - }); + return this.userRepository.findByEmail(email); } async findById(id: string, select?: string): Promise { - const data = await this.MongooseModel.findById(id, select); - if (!data) return null; + return this.userRepository.findById(id, select); + } + + async findUserByToken(token: string): Promise { + return this.userRepository.findUserByToken(token); + } + + async updatePasswordResetToken( + userId: string, + token: string, + resetTokenCount: IUserResetTokenCount + ): Promise<{ matched: number; modified: number }> { + return this.userRepository.updatePasswordResetToken(userId, token, resetTokenCount); + } + + create(data: any, options?: any): Promise { + return this.userRepository.create(data, options); + } + + update(query: any, body: any): Promise<{ matched: number; modified: number }> { + return this.userRepository.update(query, body); + } + + delete(query: any): Promise<{ acknowledged: boolean; deletedCount: number }> { + return this.userRepository.delete(query); + } + + count(query: any, limit?: number | undefined): Promise { + return this.userRepository.count(query, limit); + } + + aggregate( + query: any[], + options?: { readPreference?: 'secondaryPreferred' | 'primary' | undefined } | undefined + ): Promise { + return this.userRepository.aggregate(query, options); + } + + findOne(query: any, select?: any, options?: any): Promise { + return this.userRepository.findOne(query, select, options); + } - return this.mapEntity(data.toObject()); + find(query: any, select?: any, options?: any): Promise { + return this.userRepository.find(query, select, options); } - private hashResetToken(token: string) { - return createHash('sha256').update(token).digest('hex'); + findBatch( + query: any, + select?: string | undefined, + options?: any, + batchSize?: number | undefined + ): AsyncGenerator { + return this.userRepository.findBatch(query, select, options, batchSize); } - async findUserByToken(token: string) { - return await this.findOne({ - resetToken: this.hashResetToken(token), - }); + insertMany( + data: any, + ordered: boolean + ): Promise<{ acknowledged: boolean; insertedCount: number; insertedIds: Types.ObjectId[] }> { + return this.userRepository.insertMany(data, ordered); } - async updatePasswordResetToken(userId: string, token: string, resetTokenCount: IUserResetTokenCount) { - return await this.update( - { - _id: userId, - }, - { - $set: { - resetToken: this.hashResetToken(token), - resetTokenDate: new Date(), - resetTokenCount, - }, - } - ); + updateOne(query: any, body: any): Promise<{ matched: number; modified: number }> { + return this.userRepository.updateOne(query, body); } - async findByLoginProvider(profileId: string, provider: AuthProviderEnum): Promise { - return this.findOne({ - 'tokens.providerId': profileId, - 'tokens.provider': provider, - }); + upsertMany(data: any): Promise { + return this.userRepository.upsertMany(data); } - async userExists(userId: string) { - return !!(await this.findOne( - { - _id: userId, - }, - '_id' - )); + bulkWrite(bulkOperations: any, ordered: boolean): Promise { + return this.userRepository.bulkWrite(bulkOperations, ordered); } } diff --git a/libs/shared/package.json b/libs/shared/package.json index 48e5c44cca1..beafa2c20ba 100644 --- a/libs/shared/package.json +++ b/libs/shared/package.json @@ -38,10 +38,13 @@ } }, "dependencies": { + "@clerk/clerk-sdk-node": "^5.0.9", "class-transformer": "0.5.1", "class-validator": "0.14.0" }, "devDependencies": { + "@clerk/types": "^4.5.1", + "@types/bluebird": "^3.5.24", "@types/jest": "29.5.2", "@types/json-schema": "^7.0.15", "jest": "^27.1.0", diff --git a/libs/shared/src/dto/organization/index.ts b/libs/shared/src/dto/organization/index.ts index fb58eb24063..344a19ea6a1 100644 --- a/libs/shared/src/dto/organization/index.ts +++ b/libs/shared/src/dto/organization/index.ts @@ -1,3 +1,4 @@ export * from './create-organization.dto'; +export * from './update-external-organization.dto'; export * from './members/bulk-invite-members.dto'; export * from './members/get-invite.dto'; diff --git a/libs/shared/src/dto/organization/update-external-organization.dto.ts b/libs/shared/src/dto/organization/update-external-organization.dto.ts new file mode 100644 index 00000000000..29a74e0df44 --- /dev/null +++ b/libs/shared/src/dto/organization/update-external-organization.dto.ts @@ -0,0 +1,16 @@ +import { IsDefined, IsString, IsOptional, IsEnum } from 'class-validator'; +import { JobTitleEnum } from '../../types'; +import { ProductUseCases } from './create-organization.dto'; + +export class UpdateExternalOrganizationDto { + @IsOptional() + @IsEnum(JobTitleEnum) + jobTitle?: JobTitleEnum; + + @IsString() + @IsOptional() + domain?: string; + + @IsOptional() + productUseCases?: ProductUseCases; +} diff --git a/libs/shared/src/entities/organization/organization.interface.ts b/libs/shared/src/entities/organization/organization.interface.ts index f46173c6444..72ec56f4e7a 100644 --- a/libs/shared/src/entities/organization/organization.interface.ts +++ b/libs/shared/src/entities/organization/organization.interface.ts @@ -19,4 +19,5 @@ export interface IOrganizationEntity { createdAt: string; updatedAt: string; externalId?: string; + createdBy?: string; } diff --git a/libs/shared/src/types/auth/auth.types.ts b/libs/shared/src/types/auth/auth.types.ts index 8bd71d84e81..3d261d49ad9 100644 --- a/libs/shared/src/types/auth/auth.types.ts +++ b/libs/shared/src/types/auth/auth.types.ts @@ -1,3 +1,5 @@ +import { JwtPayload } from '@clerk/types'; + export interface IJwtClaims { _id: string; firstName?: string; @@ -11,6 +13,18 @@ export interface IJwtClaims { iss?: string; } +// JWT payload + custom claims +export type ClerkJwtPayload = JwtPayload & { + _id: string; + email: string; + lastName: string; + firstName: string; + environmentId: string; // TODO + profilePicture: string; + externalId?: string; + externalOrgId?: string; +}; + // @deprecated Use IJwtClaims instead export type UserSessionData = IJwtClaims; @@ -21,5 +35,16 @@ export enum ApiAuthSchemeEnum { export enum PassportStrategyEnum { JWT = 'jwt', + JWT_CLERK = 'jwt-clerk', HEADER_API_KEY = 'headerapikey', } + +export type SentryUser = { + id: string; + username: string; + domain: string; +}; + +export type HandledUser = (IJwtClaims & SentryUser) | false; + +export const NONE_AUTH_SCHEME = 'None'; diff --git a/libs/shared/src/types/clerk/clerk.organization-membership.types.ts b/libs/shared/src/types/clerk/clerk.organization-membership.types.ts new file mode 100644 index 00000000000..b5cb3fa9f27 --- /dev/null +++ b/libs/shared/src/types/clerk/clerk.organization-membership.types.ts @@ -0,0 +1,12 @@ +import { OrganizationMembership as ClerkOrganizationMemberships } from '@clerk/clerk-sdk-node'; +import { OrganizationCustomRoleKey } from '@clerk/types'; + +export type OrganizationMembership = ClerkOrganizationMemberships; + +export type CreateOrganizationMembershipParams = { + organizationId: string; + userId: string; + role: OrganizationMembershipRole; +}; + +export type OrganizationMembershipRole = OrganizationCustomRoleKey; diff --git a/libs/shared/src/types/clerk/clerk.organization.types.ts b/libs/shared/src/types/clerk/clerk.organization.types.ts new file mode 100644 index 00000000000..a587acffd79 --- /dev/null +++ b/libs/shared/src/types/clerk/clerk.organization.types.ts @@ -0,0 +1,41 @@ +import { Organization as ClerkOrganization } from '@clerk/clerk-sdk-node'; +import { ClerkPaginationRequest } from '@clerk/types'; +import { ProductUseCases } from '../../dto'; +import { ApiServiceLevelEnum } from '../organization'; + +export type Organization = ClerkOrganization & OrganizationMetadataParams; + +export type CreateOrganizationParams = { + name: string; + slug?: string; + createdBy: string; + maxAllowedMemberships?: number; +} & OrganizationMetadataParams; + +export type UpdateOrganizationParams = { + name?: string; + slug?: string; + maxAllowedMemberships?: number; +} & OrganizationMetadataParams; + +export type UpdateMetadataParams = OrganizationMetadataParams; + +type OrganizationPublicMetadata = { + externalOrgId?: string; + apiServiceLevel?: ApiServiceLevelEnum; + domain?: string; + productUseCases?: ProductUseCases; + defaultLocale?: string; +}; + +type OrganizationMetadataParams = { + publicMetadata?: OrganizationPublicMetadata; + privateMetadata?: OrganizationPrivateMetadata; +}; + +export type GetOrganizationMembershipListParams = ClerkPaginationRequest<{ + organizationId: string; + orderBy?: WithSign<'phone_number' | 'email_address' | 'created_at' | 'first_name' | 'last_name' | 'username'>; +}>; + +type WithSign = `+${T}` | `-${T}` | T; diff --git a/libs/shared/src/types/clerk/clerk.types.ts b/libs/shared/src/types/clerk/clerk.types.ts new file mode 100644 index 00000000000..012c41186b0 --- /dev/null +++ b/libs/shared/src/types/clerk/clerk.types.ts @@ -0,0 +1,41 @@ +import { CreateOrganizationMembershipParams, OrganizationMembership } from './clerk.organization-membership.types'; +import { + GetOrganizationMembershipListParams, + Organization, + UpdateOrganizationParams, + UpdateMetadataParams, +} from './clerk.organization.types'; +import { + UpdateUserParams, + User, + UserListParams, + GetUserOrganizationMembershipListParams, + UserMetadataParams, +} from './clerk.user.types'; + +export interface IUserAPI { + updateUser(userId: string, params?: UpdateUserParams): Promise; + updateUserMetadata(userId: string, params: UserMetadataParams): Promise; + getUser(userId: string): Promise; + getUserList(params?: UserListParams): Promise>; + deleteUser(userId: string): Promise; + getOrganizationMembershipList( + params: GetUserOrganizationMembershipListParams + ): Promise>; +} + +export interface IOrganizationAPI { + getOrganization(params: { organizationId: string }): Promise; + getOrganizationMembershipList( + params: GetOrganizationMembershipListParams + ): Promise>; + updateOrganization(organizationId: string, params?: UpdateOrganizationParams): Promise; + updateOrganizationMetadata(organizationId: string, params: UpdateMetadataParams): Promise; + deleteOrganization(organizationId: string): Promise; + createOrganizationMembership(params: CreateOrganizationMembershipParams): Promise; +} + +type PaginatedResourceResponse = { + data: T; + totalCount: number; +}; diff --git a/libs/shared/src/types/clerk/clerk.user.types.ts b/libs/shared/src/types/clerk/clerk.user.types.ts new file mode 100644 index 00000000000..4f92e80142b --- /dev/null +++ b/libs/shared/src/types/clerk/clerk.user.types.ts @@ -0,0 +1,93 @@ +import { User as ClerkUser } from '@clerk/clerk-sdk-node'; +import { ClerkPaginationRequest } from '@clerk/types'; +import { IServicesHashes } from '../../entities/user'; +import { JobTitleEnum } from '../organization'; + +export type User = ClerkUser & UserMetadataParams; + +export type UpdateUserParams = { + firstName?: string; + lastName?: string; + username?: string; + password?: string; + skipPasswordChecks?: boolean; + signOutOfOtherSessions?: boolean; + primaryEmailAddressID?: string; + primaryPhoneNumberID?: string; + primaryWeb3WalletID?: string; + profileImageID?: string; + totpSecret?: string; + backupCodes?: string[]; + externalId?: string; + createdAt?: Date; + createOrganizationEnabled?: boolean; +} & UserMetadataParams & + (UserPasswordHashingParams | object); + +export type UserListParams = ClerkPaginationRequest< + UserCountParams & { + orderBy?: WithSign< + | 'createdAt' + | 'updatedAt' + | 'emailAddress' + | 'web3wallet' + | 'firstName' + | 'lastName' + | 'phoneNumber' + | 'userName' + | 'lastActiveAt' + | 'lastSignInAt' + >; + lastActiveAtSince?: number; + organizationId?: string[]; + } +>; + +type WithSign = `+${T}` | `-${T}` | T; + +type UserCountParams = { + emailAddress?: string[]; + phoneNumber?: string[]; + username?: string[]; + web3Wallet?: string[]; + query?: string; + userId?: string[]; + externalId?: string[]; +}; + +export type UserPublicMetadata = { + profilePicture?: string | null; + showOnBoarding?: boolean; + showOnBoardingTour?: number; + servicesHashes?: IServicesHashes; + jobTitle?: JobTitleEnum; +}; + +export type UserMetadataParams = { + publicMetadata?: UserPublicMetadata; + privateMetadata?: UserPrivateMetadata; + unsafeMetadata?: UserUnsafeMetadata; +}; + +type UserPasswordHashingParams = { + passwordDigest: string; + passwordHasher: PasswordHasher; +}; + +type PasswordHasher = + | 'argon2i' + | 'argon2id' + | 'bcrypt' + | 'bcrypt_sha256_django' + | 'md5' + | 'pbkdf2_sha256' + | 'pbkdf2_sha256_django' + | 'pbkdf2_sha1' + | 'phpass' + | 'scrypt_firebase' + | 'scrypt_werkzeug' + | 'sha256'; + +export type GetUserOrganizationMembershipListParams = ClerkPaginationRequest<{ + userId: string; +}>; diff --git a/libs/shared/src/types/clerk/index.ts b/libs/shared/src/types/clerk/index.ts new file mode 100644 index 00000000000..b004a15ef44 --- /dev/null +++ b/libs/shared/src/types/clerk/index.ts @@ -0,0 +1,4 @@ +export * from './clerk.organization.types'; +export * from './clerk.user.types'; +export * from './clerk.organization-membership.types'; +export * from './clerk.types'; diff --git a/libs/shared/src/types/index.ts b/libs/shared/src/types/index.ts index cbbc948b106..75e8e73fd79 100644 --- a/libs/shared/src/types/index.ts +++ b/libs/shared/src/types/index.ts @@ -26,4 +26,5 @@ export * from './product-features'; export * from './resource-limiting'; export * from './files'; export * from './storage'; +export * from './clerk'; export * from './controls'; diff --git a/libs/shared/src/utils/env.ts b/libs/shared/src/utils/env.ts index e2698699fce..bf9791e3018 100644 --- a/libs/shared/src/utils/env.ts +++ b/libs/shared/src/utils/env.ts @@ -49,3 +49,6 @@ export const getEnvVariable = (name: string, context?: any): string => { return ''; }; + +export const isClerkEnabled = () => + (process.env.NOVU_ENTERPRISE === 'true' || process.env.CI_EE_TEST === 'true') && process.env.CLERK_ENABLED === 'true'; diff --git a/libs/testing/package.json b/libs/testing/package.json index b6f2ab4e084..6071138e7e1 100644 --- a/libs/testing/package.json +++ b/libs/testing/package.json @@ -21,6 +21,8 @@ "main": "dist/index.js", "types": "dist/index.d.ts", "dependencies": { + "@clerk/clerk-sdk-node": "^5.0.9", + "@clerk/types": "^4.5.1", "@faker-js/faker": "^6.0.0", "@novu/dal": "workspace:*", "@novu/shared": "workspace:*", @@ -34,6 +36,7 @@ "event-stream": "^4.0.1", "fs-extra": "^9.0.0", "jsonfile": "^6.0.1", + "jsonwebtoken": "9.0.0", "mongoose": "^7.5.0", "ng-intercom": "^8.0.2", "reflect-metadata": "^0.1.13", diff --git a/libs/testing/src/ee/ee.organization.service.ts b/libs/testing/src/ee/ee.organization.service.ts new file mode 100644 index 00000000000..3a909dbda5f --- /dev/null +++ b/libs/testing/src/ee/ee.organization.service.ts @@ -0,0 +1,44 @@ +import { ApiServiceLevelEnum, JobTitleEnum, MemberRoleEnum, MemberStatusEnum } from '@novu/shared'; +import { CommunityOrganizationRepository, MemberRepository, OrganizationRepository } from '@novu/dal'; +import { getEERepository } from './ee.repository.factory'; + +export class EEOrganizationService { + private organizationRepository = getEERepository('OrganizationRepository'); + private communityOrganizationRepository = new CommunityOrganizationRepository(); + private memberRepository = getEERepository('MemberRepository'); + + async createOrganization(orgId: string) { + // if internal organization exists delete so we can re-create with same Clerk org id + const org = await this.communityOrganizationRepository.findOne({ externalId: orgId }); + + if (org) { + await this.communityOrganizationRepository.delete({ _id: org._id }); + } + + const syncExternalOrg = { + externalId: orgId, + }; + + /** + * Links Clerk organization with internal organization collection + * (!) this is without org creation side-effects + */ + return this.organizationRepository.create(syncExternalOrg); + } + + async addMember(organizationId: string, userId: string) { + await this.memberRepository.addMember(organizationId, { + _userId: userId, + roles: [MemberRoleEnum.ADMIN], + memberStatus: MemberStatusEnum.ACTIVE, + }); + } + + async getOrganization(organizationId: string) { + return await this.organizationRepository.findById(organizationId); + } + + async updateServiceLevel(organizationId: string, serviceLevel: ApiServiceLevelEnum) { + await this.organizationRepository.updateServiceLevel(organizationId, serviceLevel); + } +} diff --git a/libs/testing/src/ee/ee.repository.factory.ts b/libs/testing/src/ee/ee.repository.factory.ts new file mode 100644 index 00000000000..ecbf3f1c1c0 --- /dev/null +++ b/libs/testing/src/ee/ee.repository.factory.ts @@ -0,0 +1,48 @@ +import { CommunityOrganizationRepository, CommunityUserRepository, CommunityMemberRepository } from '@novu/dal'; +import { isClerkEnabled } from '@novu/shared'; + +export function getEERepository(className: 'OrganizationRepository' | 'MemberRepository' | 'UserRepository'): T { + if (isClerkEnabled()) { + switch (className) { + case 'OrganizationRepository': + return getEEOrganizationRepository(); + case 'MemberRepository': + return getEEMemberRepository(); + case 'UserRepository': + return getEEUserRepository(); + } + } + + switch (className) { + case 'OrganizationRepository': + return new CommunityOrganizationRepository() as T; + case 'MemberRepository': + return new CommunityMemberRepository() as T; + case 'UserRepository': + return new CommunityUserRepository() as T; + } +} + +function getEEUserRepository() { + const enterpriseModule = require('@novu/ee-auth'); + const enterpriseUserRepository = enterpriseModule?.EEUserRepository; + const clerkClientMock = enterpriseModule?.ClerkClientMock; + + return new enterpriseUserRepository(new CommunityUserRepository(), new clerkClientMock()); +} + +function getEEOrganizationRepository() { + const enterpriseModule = require('@novu/ee-auth'); + const enterpriseOrganizationRepository = enterpriseModule?.EEOrganizationRepository; + const clerkClientMock = enterpriseModule?.ClerkClientMock; + + return new enterpriseOrganizationRepository(new CommunityOrganizationRepository(), new clerkClientMock()); +} + +function getEEMemberRepository() { + const enterpriseModule = require('@novu/ee-auth'); + const enterpriseMemberRepository = enterpriseModule?.EEMemberRepository; + const clerkClientMock = enterpriseModule?.ClerkClientMock; + + return new enterpriseMemberRepository(new CommunityOrganizationRepository(), new clerkClientMock()); +} diff --git a/libs/testing/src/ee/ee.user.service.ts b/libs/testing/src/ee/ee.user.service.ts new file mode 100644 index 00000000000..0651f58f300 --- /dev/null +++ b/libs/testing/src/ee/ee.user.service.ts @@ -0,0 +1,24 @@ +import { UserEntity, UserRepository } from '@novu/dal'; + +import { getEERepository } from './ee.repository.factory'; + +export class EEUserService { + private userRepository = getEERepository('UserRepository'); + + async createUser(userId: string): Promise { + // link external user to newly created internal user + const user = await this.userRepository.create({}, { linkOnly: true, externalId: userId }); + + return user; + } + + async getUser(id: string): Promise { + const user = await this.userRepository.findById(id); + + if (!user) { + throw new Error(`Test user with ${id} not found`); + } + + return user; + } +} diff --git a/libs/testing/src/environment.service.ts b/libs/testing/src/environment.service.ts index 160aac7866f..f6504a4009e 100644 --- a/libs/testing/src/environment.service.ts +++ b/libs/testing/src/environment.service.ts @@ -1,6 +1,7 @@ import { faker } from '@faker-js/faker'; import { EnvironmentRepository, EnvironmentEntity } from '@novu/dal'; import { IApiRateLimitMaximum } from '@novu/shared'; +import { createHash } from 'crypto'; import { v4 as uuid } from 'uuid'; enum EnvironmentsEnum { @@ -17,6 +18,9 @@ export class EnvironmentService { name?: string, parentId?: string ): Promise { + const key = uuid(); + const hashedApiKey = createHash('sha256').update(key).digest('hex'); + return await this.environmentRepository.create({ identifier: uuid(), name: name ?? faker.name.jobTitle(), @@ -24,8 +28,9 @@ export class EnvironmentService { ...(parentId && { _parentId: parentId }), apiKeys: [ { - key: uuid(), + key: key, _userId: userId, + hash: hashedApiKey, }, ], }); diff --git a/libs/testing/src/index.ts b/libs/testing/src/index.ts index 3cd5721afa8..6395bf2406d 100644 --- a/libs/testing/src/index.ts +++ b/libs/testing/src/index.ts @@ -13,3 +13,4 @@ export * from './user.service'; export * from './user.session'; export * from './utils'; export * from './workflow-override.service'; +export * from './ee/ee.repository.factory'; diff --git a/libs/testing/src/organization.service.ts b/libs/testing/src/organization.service.ts index 293dbab5801..46a362e1a78 100644 --- a/libs/testing/src/organization.service.ts +++ b/libs/testing/src/organization.service.ts @@ -1,11 +1,10 @@ import { ApiServiceLevelEnum, MemberRoleEnum, MemberStatusEnum } from '@novu/shared'; import { faker } from '@faker-js/faker'; -import { MemberRepository, OrganizationRepository } from '@novu/dal'; +import { CommunityMemberRepository, CommunityOrganizationRepository, OrganizationRepository } from '@novu/dal'; export class OrganizationService { - private organizationRepository = new OrganizationRepository(); - - private memberRepository = new MemberRepository(); + private organizationRepository = new CommunityOrganizationRepository(); + private memberRepository = new CommunityMemberRepository(); async createOrganization(options?: Parameters[0]) { if (options) { @@ -31,9 +30,7 @@ export class OrganizationService { } async getOrganization(organizationId: string) { - return await this.organizationRepository.findOne({ - _id: organizationId, - }); + return await this.organizationRepository.findById(organizationId); } async updateServiceLevel(organizationId: string, serviceLevel: ApiServiceLevelEnum) { diff --git a/libs/testing/src/user.service.ts b/libs/testing/src/user.service.ts index 6833b2fe778..f4a191a8928 100644 --- a/libs/testing/src/user.service.ts +++ b/libs/testing/src/user.service.ts @@ -1,5 +1,5 @@ import { faker } from '@faker-js/faker'; -import { UserEntity, UserRepository } from '@novu/dal'; +import { UserEntity, CommunityUserRepository } from '@novu/dal'; import { normalizeEmail } from '@novu/shared'; import { hash } from 'bcrypt'; @@ -10,7 +10,7 @@ import { TEST_USER_PASSWORD } from './constants'; export class UserService { private environmentService = new EnvironmentService(); private organizationService = new OrganizationService(); - private userRepository = new UserRepository(); + private userRepository = new CommunityUserRepository(); async createTestUser(): Promise { const user = await this.createUser({ @@ -47,9 +47,7 @@ export class UserService { } async getUser(id: string): Promise { - const user = await this.userRepository.findOne({ - _id: id, - }); + const user = await this.userRepository.findById(id); if (!user) { throw new Error(`Test user with ${id} not found`); diff --git a/libs/testing/src/user.session.ts b/libs/testing/src/user.session.ts index dad77da6759..18b74a189f6 100644 --- a/libs/testing/src/user.session.ts +++ b/libs/testing/src/user.session.ts @@ -1,6 +1,7 @@ import 'cross-fetch/polyfill'; import { faker } from '@faker-js/faker'; import { SuperTest, Test } from 'supertest'; +import jwt from 'jsonwebtoken'; import request from 'supertest'; import superAgentDefaults from 'superagent-defaults'; import { @@ -11,6 +12,8 @@ import { JobTopicNameEnum, StepTypeEnum, TriggerRecipientsPayload, + ClerkJwtPayload, + isClerkEnabled, } from '@novu/shared'; import { UserEntity, @@ -23,7 +26,6 @@ import { ChangeEntity, SubscriberRepository, LayoutRepository, - IntegrationRepository, } from '@novu/dal'; import { NotificationTemplateService } from './notification-template.service'; @@ -34,8 +36,20 @@ import { CreateTemplatePayload } from './create-notification-template.interface' import { IntegrationService } from './integration.service'; import { UserService } from './user.service'; import { JobsService } from './jobs.service'; +import { EEUserService } from './ee/ee.user.service'; +import { EEOrganizationService } from './ee/ee.organization.service'; import { TEST_USER_PASSWORD } from './constants'; +type UserSessionOptions = { + noOrganization?: boolean; + noEnvironment?: boolean; + showOnBoardingTour?: boolean; + ee?: { + userId: 'clerk_user_1' | 'clerk_user_2'; + orgId: 'clerk_org_1'; + }; +}; + const EMAIL_BLOCK: IEmailBlock[] = [ { type: EmailBlockTypeEnum.TEXT, @@ -47,7 +61,6 @@ export class UserSession { private notificationGroupRepository = new NotificationGroupRepository(); private feedRepository = new FeedRepository(); private layoutRepository = new LayoutRepository(); - private integrationRepository = new IntegrationRepository(); private changeRepository: ChangeRepository = new ChangeRepository(); private environmentService: EnvironmentService = new EnvironmentService(); private integrationService: IntegrationService = new IntegrationService(); @@ -81,13 +94,16 @@ export class UserSession { this.jobsService = new JobsService(); } - async initialize( - options: { - noOrganization?: boolean; - noEnvironment?: boolean; - showOnBoardingTour?: boolean; - } = {} - ) { + async initialize(options?: UserSessionOptions) { + if (isClerkEnabled()) { + // ids of preseeded Clerk resources (MongoDB: clerk_users, clerk_organizations, clerk_organization_memberships) + await this.initializeEE(options); + } else { + await this.initializeCommunity(options); + } + } + + private async initializeCommunity(options: UserSessionOptions = {}) { const card = { firstName: faker.name.firstName(), lastName: faker.name.lastName(), @@ -108,16 +124,58 @@ export class UserSession { this.user = await userService.createUser(userEntity); if (!options.noOrganization) { - await this.addOrganization(); + await this.addOrganizationCommunity(); + } + + await this.fetchJwtCommunity(); + + if (!options.noOrganization && !options?.noEnvironment) { + await this.createEnvironmentsAndFeeds(); + } + + await this.fetchJwtCommunity(); + + if (!options.noOrganization) { + if (!options?.noEnvironment) { + await this.updateOrganizationDetails(); + } + } + + if (!options.noOrganization && !options.noEnvironment) { + const { token, profile } = await this.initializeWidgetSession(); + this.subscriberToken = token; + this.subscriberProfile = profile; + } + } + + private async initializeEE(options: UserSessionOptions = { ee: { userId: 'clerk_user_1', orgId: 'clerk_org_1' } }) { + const userService = new EEUserService(); + + // user is already in org + const userId = options.ee?.userId || 'clerk_user_1'; + const orgId = options.ee?.orgId || 'clerk_org_1'; + + // already existing user in Clerk + const user = await userService.getUser(userId); + + if (!user._id) { + // not linked in clerk + this.user = await userService.createUser(userId); + } else { + this.user = user; + } + + if (!options.noOrganization) { + await this.addOrganizationEE(orgId); } - await this.fetchJWT(); + await this.fetchJwtEE(); if (!options.noOrganization && !options?.noEnvironment) { await this.createEnvironmentsAndFeeds(); } - await this.fetchJWT(); + await this.fetchJwtEE(); if (!options.noOrganization) { if (!options?.noEnvironment) { @@ -160,6 +218,22 @@ export class UserSession { } async fetchJWT() { + if (isClerkEnabled()) { + await this.fetchJwtEE(); + } else { + await this.fetchJwtCommunity(); + } + } + + async addOrganization() { + if (isClerkEnabled()) { + return await this.addOrganizationEE('clerk_org_1'); + } else { + return await this.addOrganizationCommunity(); + } + } + + private async fetchJwtCommunity() { const response = await request(this.requestEndpoint).get( `/v1/auth/test/token/${this.user._id}?environmentId=${ this.environment ? this.environment._id : '' @@ -170,6 +244,37 @@ export class UserSession { this.testAgent = superAgentDefaults(request(this.requestEndpoint)).set('Authorization', this.token); } + private async fetchJwtEE() { + await this.updateEETokenClaims({ + externalId: this.user ? this.user._id : '', + externalOrgId: this.organization ? this.organization._id : '', + environmentId: this.environment ? this.environment._id : '', + }); + } + + async updateEETokenClaims(claims: Partial) { + const decoded = await this.decodeClerkJWT(process.env.CLERK_LONG_LIVED_TOKEN as string); + + const newToken = { + ...decoded, + ...claims, + }; + + const encoded = jwt.sign(newToken, process.env.CLERK_PRIVATE_KEY as string, { + algorithm: 'RS256', + }); + + this.token = `Bearer ${encoded}`; + + this.testAgent = superAgentDefaults(request(this.requestEndpoint)).set('Authorization', this.token); + } + + private async decodeClerkJWT(token: string) { + const publicKey = process.env.CLERK_PEM_PUBLIC_KEY; + + return jwt.verify(token, publicKey); + } + async createEnvironmentsAndFeeds(): Promise { const development = await this.createEnvironment('Development'); this.environment = development; @@ -258,7 +363,7 @@ export class UserSession { }); } - async addOrganization() { + private async addOrganizationCommunity() { const organizationService = new OrganizationService(); this.organization = await organizationService.createOrganization(); @@ -267,6 +372,20 @@ export class UserSession { return this.organization; } + private async addOrganizationEE(orgId: string) { + const organizationService = new EEOrganizationService(); + + try { + // is not linked + this.organization = await organizationService.createOrganization(orgId); + } catch (e) { + // is already linked + this.organization = (await organizationService.getOrganization(orgId)) as OrganizationEntity; + } + + return this.organization; + } + async switchToProdEnvironment() { const prodEnvironment = await this.environmentService.getProductionEnvironment(this.organization._id); if (prodEnvironment) { @@ -281,6 +400,7 @@ export class UserSession { } } + // TODO: create EE version async switchEnvironment(environmentId: string) { const environment = await this.environmentService.getEnvironment(environmentId); @@ -288,7 +408,11 @@ export class UserSession { this.environment = environment; await this.testAgent.post(`/v1/auth/environments/${environmentId}/switch`); - await this.fetchJWT(); + if (isClerkEnabled()) { + await this.fetchJwtEE(); + } else { + await this.fetchJwtCommunity(); + } } } @@ -350,7 +474,7 @@ export class UserSession { } public async updateOrganizationServiceLevel(serviceLevel: ApiServiceLevelEnum) { - const organizationService = new OrganizationService(); + const organizationService = isClerkEnabled() ? new EEOrganizationService() : new OrganizationService(); await organizationService.updateServiceLevel(this.organization._id, serviceLevel); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c14664e8b16..942d827f0b3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -463,6 +463,9 @@ importers: passport-github2: specifier: ^0.1.12 version: 0.1.12 + passport-google-oauth: + specifier: ^2.0.0 + version: 2.0.0 passport-headerapikey: specifier: ^1.2.2 version: 1.2.2 @@ -1786,49 +1789,70 @@ importers: enterprise/packages/auth: dependencies: + '@clerk/clerk-sdk-node': + specifier: ^5.0.9 + version: 5.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@nestjs/common': specifier: 10.2.2 version: 10.2.2(class-transformer@0.5.1)(class-validator@0.14.0)(reflect-metadata@0.1.13)(rxjs@7.8.1) + '@nestjs/core': + specifier: '>=10' + version: 10.2.2(@nestjs/common@10.2.2(class-transformer@0.5.1)(class-validator@0.14.0)(reflect-metadata@0.1.13)(rxjs@7.8.1))(@nestjs/platform-express@10.2.2)(@nestjs/websockets@10.2.2)(encoding@0.1.13)(reflect-metadata@0.1.13)(rxjs@7.8.1) '@nestjs/jwt': specifier: 10.2.0 version: 10.2.0(@nestjs/common@10.2.2(class-transformer@0.5.1)(class-validator@0.14.0)(reflect-metadata@0.1.13)(rxjs@7.8.1)) '@nestjs/passport': specifier: 9.0.3 version: 9.0.3(@nestjs/common@10.2.2(class-transformer@0.5.1)(class-validator@0.14.0)(reflect-metadata@0.1.13)(rxjs@7.8.1))(passport@0.6.0) - '@novu/application-generic': - specifier: workspace:* - version: link:../../../libs/application-generic + '@nestjs/swagger': + specifier: ^7.1.9 + version: 7.1.9(@nestjs/common@10.2.2(class-transformer@0.5.1)(class-validator@0.14.0)(reflect-metadata@0.1.13)(rxjs@7.8.1))(@nestjs/core@10.2.2(@nestjs/common@10.2.2(class-transformer@0.5.1)(class-validator@0.14.0)(reflect-metadata@0.1.13)(rxjs@7.8.1))(@nestjs/platform-express@10.2.2)(@nestjs/websockets@10.2.2)(encoding@0.1.13)(reflect-metadata@0.1.13)(rxjs@7.8.1))(class-transformer@0.5.1)(class-validator@0.14.0)(reflect-metadata@0.1.13) '@novu/dal': specifier: workspace:* version: link:../../../libs/dal '@novu/shared': specifier: workspace:* version: link:../../../libs/shared + class-transformer: + specifier: ^0.5.1 + version: 0.5.1 + class-validator: + specifier: ^0.14.0 + version: 0.14.0 + jwks-rsa: + specifier: ^3.1.0 + version: 3.1.0 + mongoose: + specifier: ^7.5.0 + version: 7.5.2(@aws-sdk/credential-providers@3.504.1) passport: specifier: 0.6.0 version: 0.6.0 - passport-google-oauth: - specifier: ^2.0.0 - version: 2.0.0 - passport-oauth2: - specifier: ^1.6.1 - version: 1.7.0 + passport-jwt: + specifier: ^4.0.0 + version: 4.0.1 + svix: + specifier: ^1.24.0 + version: 1.24.0(encoding@0.1.13) devDependencies: - '@types/chai': - specifier: ^4.2.11 - version: 4.3.4 + '@clerk/types': + specifier: ^4.5.1 + version: 4.5.1 '@types/mocha': specifier: ^8.0.1 version: 8.2.3 '@types/node': specifier: ^20.14.10 version: 20.14.10 + '@types/passport-jwt': + specifier: ^3.0.3 + version: 3.0.8 '@types/sinon': specifier: ^9.0.0 version: 9.0.11 chai: specifier: ^4.2.0 - version: 4.3.7 + version: 4.4.1 cross-env: specifier: ^7.0.3 version: 7.0.3 @@ -2481,6 +2505,9 @@ importers: specifier: ^1.4.6 version: 1.6.6 optionalDependencies: + '@novu/ee-auth': + specifier: workspace:* + version: link:../../enterprise/packages/auth '@novu/ee-bridge-worker': specifier: workspace:* version: link:../../enterprise/packages/bridge-worker @@ -2618,6 +2645,9 @@ importers: '@faker-js/faker': specifier: ^6.0.0 version: 6.3.1 + '@nestjs/common': + specifier: 10.2.2 + version: 10.2.2(class-transformer@0.5.1)(class-validator@0.14.0)(reflect-metadata@0.1.13)(rxjs@7.8.1) '@novu/shared': specifier: workspace:* version: link:../shared @@ -2923,7 +2953,7 @@ importers: dependencies: '@mantine/code-highlight': specifier: ^7.10.2 - version: 7.10.2(@mantine/core@7.10.1(@mantine/hooks@7.10.1(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.10.1(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 7.11.1(@mantine/core@7.10.1(@mantine/hooks@7.10.1(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.10.1(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@mantine/core': specifier: ^7.10.0 version: 7.10.1(@mantine/hooks@7.10.1(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -3051,6 +3081,9 @@ importers: libs/shared: dependencies: + '@clerk/clerk-sdk-node': + specifier: ^5.0.9 + version: 5.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) class-transformer: specifier: 0.5.1 version: 0.5.1 @@ -3058,6 +3091,12 @@ importers: specifier: 0.14.0 version: 0.14.0 devDependencies: + '@clerk/types': + specifier: ^4.5.1 + version: 4.5.1 + '@types/bluebird': + specifier: ^3.5.24 + version: 3.5.38 '@types/jest': specifier: 29.5.2 version: 29.5.2 @@ -3076,6 +3115,12 @@ importers: libs/testing: dependencies: + '@clerk/clerk-sdk-node': + specifier: ^5.0.9 + version: 5.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@clerk/types': + specifier: ^4.5.1 + version: 4.5.1 '@faker-js/faker': specifier: ^6.0.0 version: 6.3.1 @@ -3115,6 +3160,9 @@ importers: jsonfile: specifier: ^6.0.1 version: 6.1.0 + jsonwebtoken: + specifier: 9.0.0 + version: 9.0.0 mongoose: specifier: ^7.5.0 version: 7.5.2(@aws-sdk/credential-providers@3.504.1) @@ -3370,7 +3418,7 @@ importers: version: 13.5.6(@babel/core@7.24.4)(@opentelemetry/api@1.7.0)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.64.1) prettier: specifier: ^3.2.5 - version: 3.2.5 + version: 3.3.2 ts-node: specifier: ^10.9.2 version: 10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.2))(@types/node@20.14.10)(typescript@5.4.5) @@ -3474,10 +3522,10 @@ importers: version: 5.3.0 compression-webpack-plugin: specifier: ^10.0.0 - version: 10.0.0(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.20.1)(webpack-cli@5.1.4)) + version: 10.0.0(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.21.4)(webpack-cli@5.1.4)) esbuild-plugin-compress: specifier: ^1.0.1 - version: 1.0.1(esbuild@0.20.1) + version: 1.0.1(esbuild@0.21.4) eslint-plugin-local-rules: specifier: ^3.0.2 version: 3.0.2 @@ -3492,7 +3540,7 @@ importers: version: 1.16.1(postcss@8.4.38) postcss-preset-env: specifier: ^9.5.14 - version: 9.5.14(postcss@8.4.38) + version: 9.6.0(postcss@8.4.38) solid-devtools: specifier: ^0.29.2 version: 0.29.3(solid-js@1.8.17)(vite@5.1.7(@types/node@20.14.10)) @@ -3501,28 +3549,28 @@ importers: version: 3.4.4(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.2))(@types/node@20.14.10)(typescript@4.9.5)) terser-webpack-plugin: specifier: ^5.3.9 - version: 5.3.9(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.20.1)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.20.1)(webpack-cli@5.1.4)) + version: 5.3.9(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.21.4)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.21.4)(webpack-cli@5.1.4)) tiny-glob: specifier: ^0.2.9 version: 0.2.9 ts-jest: specifier: ^29.0.3 - version: 29.1.2(@babel/core@7.24.4)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.4))(esbuild@0.20.1)(jest@29.7.0(@types/node@20.14.10)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.2))(@types/node@20.14.10)(typescript@4.9.5)))(typescript@4.9.5) + version: 29.1.2(@babel/core@7.24.4)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.4))(esbuild@0.21.4)(jest@29.7.0(@types/node@20.14.10)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.2))(@types/node@20.14.10)(typescript@4.9.5)))(typescript@4.9.5) ts-loader: specifier: ~9.4.0 - version: 9.4.2(typescript@4.9.5)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.20.1)(webpack-cli@5.1.4)) + version: 9.4.2(typescript@4.9.5)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.21.4)(webpack-cli@5.1.4)) tsup: specifier: ^8.0.2 version: 8.0.2(@microsoft/api-extractor@7.38.0(@types/node@20.14.10))(@swc/core@1.3.107(@swc/helpers@0.5.2))(postcss@8.4.38)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.2))(@types/node@20.14.10)(typescript@4.9.5))(typescript@4.9.5) tsup-preset-solid: specifier: ^2.2.0 - version: 2.2.0(esbuild@0.20.1)(solid-js@1.8.17)(tsup@8.0.2(@microsoft/api-extractor@7.38.0(@types/node@20.14.10))(@swc/core@1.3.107(@swc/helpers@0.5.2))(postcss@8.4.38)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.2))(@types/node@20.14.10)(typescript@4.9.5))(typescript@4.9.5)) + version: 2.2.0(esbuild@0.21.4)(solid-js@1.8.17)(tsup@8.0.2(@microsoft/api-extractor@7.38.0(@types/node@20.14.10))(@swc/core@1.3.107(@swc/helpers@0.5.2))(postcss@8.4.38)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.2))(@types/node@20.14.10)(typescript@4.9.5))(typescript@4.9.5)) typescript: specifier: 4.9.5 version: 4.9.5 webpack: specifier: ^5.74.0 - version: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.20.1)(webpack-cli@5.1.4) + version: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.21.4)(webpack-cli@5.1.4) webpack-bundle-analyzer: specifier: ^4.9.0 version: 4.10.1 @@ -3647,7 +3695,7 @@ importers: version: 0.0.0 ts-jest: specifier: ^29.1.2 - version: 29.1.2(@babel/core@7.24.4)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.4))(esbuild@0.20.1)(jest@29.7.0(@types/node@20.14.10)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.2))(@types/node@20.14.10)(typescript@4.9.5)))(typescript@4.9.5) + version: 29.1.2(@babel/core@7.24.4)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.4))(esbuild@0.21.4)(jest@29.7.0(@types/node@20.14.10)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.2))(@types/node@20.14.10)(typescript@4.9.5)))(typescript@4.9.5) typedoc: specifier: ^0.24.0 version: 0.24.6(typescript@4.9.5) @@ -6493,6 +6541,30 @@ packages: bundledDependencies: - is-unicode-supported + '@clerk/backend@1.2.1': + resolution: {integrity: sha512-4NxL0VU042dgrhDTqvCFws9v5Kmg+VlA70fD0sQWWBQJxNr2pEnjHfKG21ta7qIqexXPk4Ftr0qZk2/wRiex3A==} + engines: {node: '>=18.17.0'} + + '@clerk/clerk-sdk-node@5.0.9': + resolution: {integrity: sha512-j9L+M09ZnHczR/X4uWLPTIx6gS26Ru7d45FZN3E/TjQYga7yfenaGyFaGZyrkO7h/KcZ/JQBaHIQn6640uinzQ==} + engines: {node: '>=18.17.0'} + + '@clerk/shared@2.2.1': + resolution: {integrity: sha512-LtaHZLj/T2y9/MuB7IlVXs+HzX5eGkXkXqcBGgE//OlaNYw3zo1CueEVLG9Wm30FlPwVeSnaMYWklOUpSzMVng==} + engines: {node: '>=18.17.0'} + peerDependencies: + react: '>=18 || >=19.0.0-beta' + react-dom: '>=18 || >=19.0.0-beta' + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + + '@clerk/types@4.5.1': + resolution: {integrity: sha512-eLaH+IKnxgjGQhRZ5rhZA9pQszSKbtSZE5V6c3a/F2crlkYIFABrVdf1q6p5bSAEmcYdcV4u4kaEFZ5UpYNcOw==} + engines: {node: '>=18.17.0'} + '@codexteam/icons@0.0.4': resolution: {integrity: sha512-V8N/TY2TGyas4wLrPIFq7bcow68b3gu8DfDt1+rrHPtXxcexadKauRJL6eQgfG7Z0LCrN4boLRawR4S9gjIh/Q==} @@ -6813,47 +6885,47 @@ packages: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} - '@csstools/cascade-layer-name-parser@1.0.11': - resolution: {integrity: sha512-yhsonEAhaWRQvHFYhSzOUobH2Ev++fMci+ppFRagw0qVSPlcPV4FnNmlwpM/b2BM10ZeMRkVV4So6YRswD0O0w==} + '@csstools/cascade-layer-name-parser@1.0.13': + resolution: {integrity: sha512-MX0yLTwtZzr82sQ0zOjqimpZbzjMaK/h2pmlrLK7DCzlmiZLYFpoO94WmN1akRVo6ll/TdpHb53vihHLUMyvng==} engines: {node: ^14 || ^16 || >=18} peerDependencies: - '@csstools/css-parser-algorithms': ^2.6.3 - '@csstools/css-tokenizer': ^2.3.1 + '@csstools/css-parser-algorithms': ^2.7.1 + '@csstools/css-tokenizer': ^2.4.1 - '@csstools/color-helpers@4.2.0': - resolution: {integrity: sha512-hJJrSBzbfGxUsaR6X4Bzd/FLx0F1ulKnR5ljY9AiXCtsR+H+zSWQDFWlKES1BRaVZTDHLpIIHS9K2o0h+JLlrg==} + '@csstools/color-helpers@4.2.1': + resolution: {integrity: sha512-CEypeeykO9AN7JWkr1OEOQb0HRzZlPWGwV0Ya6DuVgFdDi6g3ma/cPZ5ZPZM4AWQikDpq/0llnGGlIL+j8afzw==} engines: {node: ^14 || ^16 || >=18} - '@csstools/css-calc@1.2.2': - resolution: {integrity: sha512-0owrl7AruDRKAxoSIW8XzJdz7GnuW3AOj4rYLfmXsoKIX2ZZzttzGXoiC8n8V08X7wIBlEWWVB4C8fAN18+I6Q==} + '@csstools/css-calc@1.2.4': + resolution: {integrity: sha512-tfOuvUQeo7Hz+FcuOd3LfXVp+342pnWUJ7D2y8NUpu1Ww6xnTbHLpz018/y6rtbHifJ3iIEf9ttxXd8KG7nL0Q==} engines: {node: ^14 || ^16 || >=18} peerDependencies: - '@csstools/css-parser-algorithms': ^2.6.3 - '@csstools/css-tokenizer': ^2.3.1 + '@csstools/css-parser-algorithms': ^2.7.1 + '@csstools/css-tokenizer': ^2.4.1 - '@csstools/css-color-parser@2.0.2': - resolution: {integrity: sha512-Agx2YmxTcZ7TfB7KNZQ+iekaxbWSdblvtA35aTwE3KfuYyjOlCg3P4KGGdQF/cjm1pHWVSBo5duF/BRfZ8s07A==} + '@csstools/css-color-parser@2.0.4': + resolution: {integrity: sha512-yUb0mk/k2yVNcQvRmd9uikpu6D0aamFJGgU++5d0lng6ucaJkhKyhDCQCj9rVuQYntvFQKqyU6UfTPQWU2UkXQ==} engines: {node: ^14 || ^16 || >=18} peerDependencies: - '@csstools/css-parser-algorithms': ^2.6.3 - '@csstools/css-tokenizer': ^2.3.1 + '@csstools/css-parser-algorithms': ^2.7.1 + '@csstools/css-tokenizer': ^2.4.1 - '@csstools/css-parser-algorithms@2.6.3': - resolution: {integrity: sha512-xI/tL2zxzEbESvnSxwFgwvy5HS00oCXxL4MLs6HUiDcYfwowsoQaABKxUElp1ARITrINzBnsECOc1q0eg2GOrA==} + '@csstools/css-parser-algorithms@2.7.1': + resolution: {integrity: sha512-2SJS42gxmACHgikc1WGesXLIT8d/q2l0UFM7TaEeIzdFCE/FPMtTiizcPGGJtlPo2xuQzY09OhrLTzRxqJqwGw==} engines: {node: ^14 || ^16 || >=18} peerDependencies: - '@csstools/css-tokenizer': ^2.3.1 + '@csstools/css-tokenizer': ^2.4.1 - '@csstools/css-tokenizer@2.3.1': - resolution: {integrity: sha512-iMNHTyxLbBlWIfGtabT157LH9DUx9X8+Y3oymFEuMj8HNc+rpE3dPFGFgHjpKfjeFDjLjYIAIhXPGvS2lKxL9g==} + '@csstools/css-tokenizer@2.4.1': + resolution: {integrity: sha512-eQ9DIktFJBhGjioABJRtUucoWR2mwllurfnM8LuNGAqX3ViZXaUchqk+1s7jjtkFiT9ySdACsFEA3etErkALUg==} engines: {node: ^14 || ^16 || >=18} - '@csstools/media-query-list-parser@2.1.11': - resolution: {integrity: sha512-uox5MVhvNHqitPP+SynrB1o8oPxPMt2JLgp5ghJOWf54WGQ5OKu47efne49r1SWqs3wRP8xSWjnO9MBKxhB1dA==} + '@csstools/media-query-list-parser@2.1.13': + resolution: {integrity: sha512-XaHr+16KRU9Gf8XLi3q8kDlI18d5vzKSKCY510Vrtc9iNR0NJzbY9hhTmwhzYZj/ZwGL4VmB3TA9hJW0Um2qFA==} engines: {node: ^14 || ^16 || >=18} peerDependencies: - '@csstools/css-parser-algorithms': ^2.6.3 - '@csstools/css-tokenizer': ^2.3.1 + '@csstools/css-parser-algorithms': ^2.7.1 + '@csstools/css-tokenizer': ^2.4.1 '@csstools/normalize.css@12.0.0': resolution: {integrity: sha512-M0qqxAcwCsIVfpFQSlGN5XjXWu8l5JDZN+fPt1LeW5SZexQTgnaEvgXAY+CeygRw0EeppWHi12JxESWiWrB0Sg==} @@ -6882,20 +6954,26 @@ packages: peerDependencies: postcss: ^8.4.31 - '@csstools/postcss-color-function@3.0.16': - resolution: {integrity: sha512-KtmXfckANSKsLBoTQCzggvKft1cmmmDKYjFO4yVlB23nWUgGInVBTE9T5JLmH29NNdTWSEPLWPUxoQ6XiIEn2Q==} + '@csstools/postcss-color-function@3.0.19': + resolution: {integrity: sha512-d1OHEXyYGe21G3q88LezWWx31ImEDdmINNDy0LyLNN9ChgN2bPxoubUPiHf9KmwypBMaHmNcMuA/WZOKdZk/Lg==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + postcss: ^8.4.31 + + '@csstools/postcss-color-mix-function@2.0.19': + resolution: {integrity: sha512-mLvQlMX+keRYr16AuvuV8WYKUwF+D0DiCqlBdvhQ0KYEtcQl9/is9Ssg7RcIys8x0jIn2h1zstS4izckdZj9wg==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4.31 - '@csstools/postcss-color-mix-function@2.0.16': - resolution: {integrity: sha512-BJnD1M5Pdypl1cJuwGuzVC52PqgzaObsDLu34jgf+QU7daVFqz432PvpqvXTmfTSNt4OckOT1QIzWexEFlDNXw==} + '@csstools/postcss-content-alt-text@1.0.0': + resolution: {integrity: sha512-SkHdj7EMM/57GVvSxSELpUg7zb5eAndBeuvGwFzYtU06/QXJ/h9fuK7wO5suteJzGhm3GDF/EWPCdWV2h1IGHQ==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4.31 - '@csstools/postcss-exponential-functions@1.0.7': - resolution: {integrity: sha512-9usBPQX74OhiF/VuaVrp44UAPzqbKNyoaxEa6tbEXiFp+OAm3yB/TLRKyPUWg5tvvHGCduGJVdJJB3w8c8NBtA==} + '@csstools/postcss-exponential-functions@1.0.9': + resolution: {integrity: sha512-x1Avr15mMeuX7Z5RJUl7DmjhUtg+Amn5DZRD0fQ2TlTFTcJS8U1oxXQ9e5mA62S2RJgUU6db20CRoJyDvae2EQ==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4.31 @@ -6912,14 +6990,14 @@ packages: peerDependencies: postcss: ^8.4.31 - '@csstools/postcss-gamut-mapping@1.0.9': - resolution: {integrity: sha512-JmOeiBJj1RJriAkr+aLBaiYUpEqdNOIo3ERQ5a4uNzy18upzrQ6tz7m2Vt1GQpJ62zQj7rC5PjAhCoZCoyE31g==} + '@csstools/postcss-gamut-mapping@1.0.11': + resolution: {integrity: sha512-KrHGsUPXRYxboXmJ9wiU/RzDM7y/5uIefLWKFSc36Pok7fxiPyvkSHO51kh+RLZS1W5hbqw9qaa6+tKpTSxa5g==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4.31 - '@csstools/postcss-gradients-interpolation-method@4.0.17': - resolution: {integrity: sha512-qSNIqzLPKd2SadfWwHZv42lDRyYlLaM+Vx5rRIsnYCZbQxzFfe1XAwssrcCsHgba5bA6bi5oDoFCx0W+PRCpfw==} + '@csstools/postcss-gradients-interpolation-method@4.0.20': + resolution: {integrity: sha512-ZFl2JBHano6R20KB5ZrB8KdPM2pVK0u+/3cGQ2T8VubJq982I2LSOvQ4/VtxkAXjkPkk1rXt4AD1ni7UjTZ1Og==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4.31 @@ -6930,8 +7008,8 @@ packages: peerDependencies: postcss: ^8.4.31 - '@csstools/postcss-hwb-function@3.0.15': - resolution: {integrity: sha512-l34fRiZ7o5+pULv7OplXniBTU4TuKYNNOv0abuvUanddWGSy3+YHlMKUSgcVFo0d1DorxPAhJSTCrugl+4OmMQ==} + '@csstools/postcss-hwb-function@3.0.18': + resolution: {integrity: sha512-3ifnLltR5C7zrJ+g18caxkvSRnu9jBBXCYgnBznRjxm6gQJGnnCO9H6toHfywNdNr/qkiVf2dymERPQLDnjLRQ==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4.31 @@ -6942,8 +7020,8 @@ packages: peerDependencies: postcss: ^8.4.31 - '@csstools/postcss-ic-unit@3.0.6': - resolution: {integrity: sha512-fHaU9C/sZPauXMrzPitZ/xbACbvxbkPpHoUgB9Kw5evtsBWdVkVrajOyiT9qX7/c+G1yjApoQjP1fQatldsy9w==} + '@csstools/postcss-ic-unit@3.0.7': + resolution: {integrity: sha512-YoaNHH2wNZD+c+rHV02l4xQuDpfR8MaL7hD45iJyr+USwvr0LOheeytJ6rq8FN6hXBmEeoJBeXXgGmM8fkhH4g==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4.31 @@ -6966,8 +7044,8 @@ packages: peerDependencies: postcss: ^8.4.31 - '@csstools/postcss-light-dark-function@1.0.5': - resolution: {integrity: sha512-kKM9dtEaVmSTb3scL2pgef62KyWv6SK19JiAnCCuiDhlRE6PADKzaPPBXmP3qj4IEgIH+cQhdEosB0eroU6Fnw==} + '@csstools/postcss-light-dark-function@1.0.8': + resolution: {integrity: sha512-x0UtpCyVnERsplUeoaY6nEtp1HxTf4lJjoK/ULEm40DraqFfUdUSt76yoOyX5rGY6eeOUOkurHyYlFHVKv/pew==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4.31 @@ -6996,20 +7074,20 @@ packages: peerDependencies: postcss: ^8.4.31 - '@csstools/postcss-logical-viewport-units@2.0.9': - resolution: {integrity: sha512-iBBJuExgHwedFH9AqNOHWzZFgYnt17zhu1qWjmSihu1P5pw0lIG9q5t3uIgJJFDNmYoOGfBKan66z9u1QH8yBQ==} + '@csstools/postcss-logical-viewport-units@2.0.11': + resolution: {integrity: sha512-ElITMOGcjQtvouxjd90WmJRIw1J7KMP+M+O87HaVtlgOOlDt1uEPeTeii8qKGe2AiedEp0XOGIo9lidbiU2Ogg==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4.31 - '@csstools/postcss-media-minmax@1.1.6': - resolution: {integrity: sha512-bc0frf2Lod53j6wEHVsaVElfvCf6uhc96v99M/wUfer4MmNYfO3YLx1kFuB8xXvb0AXiWx4fohCJqemHV3bfRg==} + '@csstools/postcss-media-minmax@1.1.8': + resolution: {integrity: sha512-KYQCal2i7XPNtHAUxCECdrC7tuxIWQCW+s8eMYs5r5PaAiVTeKwlrkRS096PFgojdNCmHeG0Cb7njtuNswNf+w==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4.31 - '@csstools/postcss-media-queries-aspect-ratio-number-values@2.0.9': - resolution: {integrity: sha512-PR0s3tFSxPoKoPLoKuiZuYhwQC5bQxq/gFfywX2u/kh8rMzesARPZYKxE71I3jHWi6KDHGZl9Xb5xcFPwtvLiQ==} + '@csstools/postcss-media-queries-aspect-ratio-number-values@2.0.11': + resolution: {integrity: sha512-YD6jrib20GRGQcnOu49VJjoAnQ/4249liuz7vTpy/JfgqQ1Dlc5eD4HPUMNLOw9CWey9E6Etxwf/xc/ZF8fECA==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4.31 @@ -7044,8 +7122,8 @@ packages: peerDependencies: postcss: ^8.4.31 - '@csstools/postcss-oklab-function@3.0.16': - resolution: {integrity: sha512-zm8nND+EraZrmbO4mgcT8FrJrAQUfWNfMmbV5uTCpWtAcO5ycX3E3bO8T1TjczKYRxC5QMM/91n9YExYCF4Mvw==} + '@csstools/postcss-oklab-function@3.0.19': + resolution: {integrity: sha512-e3JxXmxjU3jpU7TzZrsNqSX4OHByRC3XjItV3Ieo/JEQmLg5rdOL4lkv/1vp27gXemzfNt44F42k/pn0FpE21Q==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4.31 @@ -7056,14 +7134,14 @@ packages: peerDependencies: postcss: ^8.4.31 - '@csstools/postcss-progressive-custom-properties@3.2.0': - resolution: {integrity: sha512-BZlirVxCRgKlE7yVme+Xvif72eTn1MYXj8oZ4Knb+jwaH4u3AN1DjbhM7j86RP5vvuAOexJ4JwfifYYKWMN/QQ==} + '@csstools/postcss-progressive-custom-properties@3.3.0': + resolution: {integrity: sha512-W2oV01phnILaRGYPmGFlL2MT/OgYjQDrL9sFlbdikMFi6oQkFki9B86XqEWR7HCsTZFVq7dbzr/o71B75TKkGg==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4.31 - '@csstools/postcss-relative-color-syntax@2.0.16': - resolution: {integrity: sha512-TSM8fVqJkT8JZDranZPnkpxjU/Q1sNR192lXMND+EcKOUjYa6uYpGSfHgjnWjCRiBSciettS+sL7y9wmnas7qQ==} + '@csstools/postcss-relative-color-syntax@2.0.19': + resolution: {integrity: sha512-MxUMSNvio1WwuS6WRLlQuv6nNPXwIWUFzBBAvL/tBdWfiKjiJnAa6eSSN5gtaacSqUkQ/Ce5Z1OzLRfeaWhADA==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4.31 @@ -7080,8 +7158,8 @@ packages: peerDependencies: postcss: ^8.4.31 - '@csstools/postcss-stepped-value-functions@3.0.8': - resolution: {integrity: sha512-X76+thsvsmH/SkqVbN+vjeFKe1ABGLRx8/Wl68QTb/zvJWdzgx5S/nbszZP5O3nTRc5eI8NxIOrQUiy30fR+0g==} + '@csstools/postcss-stepped-value-functions@3.0.10': + resolution: {integrity: sha512-MZwo0D0TYrQhT5FQzMqfy/nGZ28D1iFtpN7Su1ck5BPHS95+/Y5O9S4kEvo76f2YOsqwYcT8ZGehSI1TnzuX2g==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4.31 @@ -7092,8 +7170,8 @@ packages: peerDependencies: postcss: ^8.4.31 - '@csstools/postcss-text-decoration-shorthand@3.0.6': - resolution: {integrity: sha512-Q8HEu4AEiwNVZBD6+DpQ8M9SajpMow4+WtmndWIAv8qxDtDYL4JK1xXWkhOGk28PrcJawOvkrEZ8Ri59UN1TJw==} + '@csstools/postcss-text-decoration-shorthand@3.0.7': + resolution: {integrity: sha512-+cptcsM5r45jntU6VjotnkC9GteFR7BQBfZ5oW7inLCxj7AfLGAzMbZ60hKTP13AULVZBdxky0P8um0IBfLHVA==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4.31 @@ -7104,8 +7182,8 @@ packages: peerDependencies: postcss: ^8.4.31 - '@csstools/postcss-trigonometric-functions@3.0.8': - resolution: {integrity: sha512-zEzyGriPqoIYFgHJqWNy8bmoxjM4+ONyTap1ZzQK/Lll/VsCYvx0IckB33W/u89uLSVeeB8xC7uTrkoQ7ogKyQ==} + '@csstools/postcss-trigonometric-functions@3.0.10': + resolution: {integrity: sha512-G9G8moTc2wiad61nY5HfvxLiM/myX0aYK4s1x8MQlPH29WDPxHQM7ghGgvv2qf2xH+rrXhztOmjGHJj4jsEqXw==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4.31 @@ -7350,6 +7428,12 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.21.4': + resolution: {integrity: sha512-Zrm+B33R4LWPLjDEVnEqt2+SLTATlru1q/xYKVn8oVTbiRBGmK2VIMoIYGJDGyftnGaC788IuzGFAlb7IQ0Y8A==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.18.17': resolution: {integrity: sha512-9np+YYdNDed5+Jgr1TdWBsozZ85U1Oa3xW0c7TWqH0y2aGghXtZsuT8nYRbzOMcl0bXZXjOGbksoTtVOlWrRZg==} engines: {node: '>=12'} @@ -7374,6 +7458,12 @@ packages: cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.21.4': + resolution: {integrity: sha512-fYFnz+ObClJ3dNiITySBUx+oNalYUT18/AryMxfovLkYWbutXsct3Wz2ZWAcGGppp+RVVX5FiXeLYGi97umisA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.18.17': resolution: {integrity: sha512-wHsmJG/dnL3OkpAcwbgoBTTMHVi4Uyou3F5mf58ZtmUyIKfcdA7TROav/6tCzET4A3QW2Q2FC+eFneMU+iyOxg==} engines: {node: '>=12'} @@ -7398,6 +7488,12 @@ packages: cpu: [arm] os: [android] + '@esbuild/android-arm@0.21.4': + resolution: {integrity: sha512-E7H/yTd8kGQfY4z9t3nRPk/hrhaCajfA3YSQSBrst8B+3uTcgsi8N+ZWYCaeIDsiVs6m65JPCaQN/DxBRclF3A==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.18.17': resolution: {integrity: sha512-O+FeWB/+xya0aLg23hHEM2E3hbfwZzjqumKMSIqcHbNvDa+dza2D0yLuymRBQQnC34CWrsJUXyH2MG5VnLd6uw==} engines: {node: '>=12'} @@ -7422,6 +7518,12 @@ packages: cpu: [x64] os: [android] + '@esbuild/android-x64@0.21.4': + resolution: {integrity: sha512-mDqmlge3hFbEPbCWxp4fM6hqq7aZfLEHZAKGP9viq9wMUBVQx202aDIfc3l+d2cKhUJM741VrCXEzRFhPDKH3Q==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.18.17': resolution: {integrity: sha512-M9uJ9VSB1oli2BE/dJs3zVr9kcCBBsE883prage1NWz6pBS++1oNn/7soPNS3+1DGj0FrkSvnED4Bmlu1VAE9g==} engines: {node: '>=12'} @@ -7446,6 +7548,12 @@ packages: cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.21.4': + resolution: {integrity: sha512-72eaIrDZDSiWqpmCzVaBD58c8ea8cw/U0fq/PPOTqE3c53D0xVMRt2ooIABZ6/wj99Y+h4ksT/+I+srCDLU9TA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.18.17': resolution: {integrity: sha512-XDre+J5YeIJDMfp3n0279DFNrGCXlxOuGsWIkRb1NThMZ0BsrWXoTg23Jer7fEXQ9Ye5QjrvXpxnhzl3bHtk0g==} engines: {node: '>=12'} @@ -7470,6 +7578,12 @@ packages: cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.21.4': + resolution: {integrity: sha512-uBsuwRMehGmw1JC7Vecu/upOjTsMhgahmDkWhGLWxIgUn2x/Y4tIwUZngsmVb6XyPSTXJYS4YiASKPcm9Zitag==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.18.17': resolution: {integrity: sha512-cjTzGa3QlNfERa0+ptykyxs5A6FEUQQF0MuilYXYBGdBxD3vxJcKnzDlhDCa1VAJCmAxed6mYhA2KaJIbtiNuQ==} engines: {node: '>=12'} @@ -7494,6 +7608,12 @@ packages: cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.21.4': + resolution: {integrity: sha512-8JfuSC6YMSAEIZIWNL3GtdUT5NhUA/CMUCpZdDRolUXNAXEE/Vbpe6qlGLpfThtY5NwXq8Hi4nJy4YfPh+TwAg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.18.17': resolution: {integrity: sha512-sOxEvR8d7V7Kw8QqzxWc7bFfnWnGdaFBut1dRUYtu+EIRXefBc/eIsiUiShnW0hM3FmQ5Zf27suDuHsKgZ5QrA==} engines: {node: '>=12'} @@ -7518,6 +7638,12 @@ packages: cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.21.4': + resolution: {integrity: sha512-8d9y9eQhxv4ef7JmXny7591P/PYsDFc4+STaxC1GBv0tMyCdyWfXu2jBuqRsyhY8uL2HU8uPyscgE2KxCY9imQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.18.17': resolution: {integrity: sha512-c9w3tE7qA3CYWjT+M3BMbwMt+0JYOp3vCMKgVBrCl1nwjAlOMYzEo+gG7QaZ9AtqZFj5MbUc885wuBBmu6aADQ==} engines: {node: '>=12'} @@ -7542,6 +7668,12 @@ packages: cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.21.4': + resolution: {integrity: sha512-/GLD2orjNU50v9PcxNpYZi+y8dJ7e7/LhQukN3S4jNDXCKkyyiyAz9zDw3siZ7Eh1tRcnCHAo/WcqKMzmi4eMQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.18.17': resolution: {integrity: sha512-2d3Lw6wkwgSLC2fIvXKoMNGVaeY8qdN0IC3rfuVxJp89CRfA3e3VqWifGDfuakPmp90+ZirmTfye1n4ncjv2lg==} engines: {node: '>=12'} @@ -7566,6 +7698,12 @@ packages: cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.21.4': + resolution: {integrity: sha512-2rqFFefpYmpMs+FWjkzSgXg5vViocqpq5a1PSRgT0AvSgxoXmGF17qfGAzKedg6wAwyM7UltrKVo9kxaJLMF/g==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.18.17': resolution: {integrity: sha512-1DS9F966pn5pPnqXYz16dQqWIB0dmDfAQZd6jSSpiT9eX1NzKh07J6VKR3AoXXXEk6CqZMojiVDSZi1SlmKVdg==} engines: {node: '>=12'} @@ -7590,6 +7728,12 @@ packages: cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.21.4': + resolution: {integrity: sha512-pNftBl7m/tFG3t2m/tSjuYeWIffzwAZT9m08+9DPLizxVOsUl8DdFzn9HvJrTQwe3wvJnwTdl92AonY36w/25g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.18.17': resolution: {integrity: sha512-EvLsxCk6ZF0fpCB6w6eOI2Fc8KW5N6sHlIovNe8uOFObL2O+Mr0bflPHyHwLT6rwMg9r77WOAWb2FqCQrVnwFg==} engines: {node: '>=12'} @@ -7614,6 +7758,12 @@ packages: cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.21.4': + resolution: {integrity: sha512-cSD2gzCK5LuVX+hszzXQzlWya6c7hilO71L9h4KHwqI4qeqZ57bAtkgcC2YioXjsbfAv4lPn3qe3b00Zt+jIfQ==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.18.17': resolution: {integrity: sha512-e0bIdHA5p6l+lwqTE36NAW5hHtw2tNRmHlGBygZC14QObsA3bD4C6sXLJjvnDIjSKhW1/0S3eDy+QmX/uZWEYQ==} engines: {node: '>=12'} @@ -7638,6 +7788,12 @@ packages: cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.21.4': + resolution: {integrity: sha512-qtzAd3BJh7UdbiXCrg6npWLYU0YpufsV9XlufKhMhYMJGJCdfX/G6+PNd0+v877X1JG5VmjBLUiFB0o8EUSicA==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.18.17': resolution: {integrity: sha512-BAAilJ0M5O2uMxHYGjFKn4nJKF6fNCdP1E0o5t5fvMYYzeIqy2JdAP88Az5LHt9qBoUa4tDaRpfWt21ep5/WqQ==} engines: {node: '>=12'} @@ -7662,6 +7818,12 @@ packages: cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.21.4': + resolution: {integrity: sha512-yB8AYzOTaL0D5+2a4xEy7OVvbcypvDR05MsB/VVPVA7nL4hc5w5Dyd/ddnayStDgJE59fAgNEOdLhBxjfx5+dg==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.18.17': resolution: {integrity: sha512-Wh/HW2MPnC3b8BqRSIme/9Zhab36PPH+3zam5pqGRH4pE+4xTrVLx2+XdGp6fVS3L2x+DrsIcsbMleex8fbE6g==} engines: {node: '>=12'} @@ -7686,6 +7848,12 @@ packages: cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.21.4': + resolution: {integrity: sha512-Y5AgOuVzPjQdgU59ramLoqSSiXddu7F3F+LI5hYy/d1UHN7K5oLzYBDZe23QmQJ9PIVUXwOdKJ/jZahPdxzm9w==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.18.17': resolution: {integrity: sha512-j/34jAl3ul3PNcK3pfI0NSlBANduT2UO5kZ7FCaK33XFv3chDhICLY8wJJWIhiQ+YNdQ9dxqQctRg2bvrMlYgg==} engines: {node: '>=12'} @@ -7710,6 +7878,12 @@ packages: cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.21.4': + resolution: {integrity: sha512-Iqc/l/FFwtt8FoTK9riYv9zQNms7B8u+vAI/rxKuN10HgQIXaPzKZc479lZ0x6+vKVQbu55GdpYpeNWzjOhgbA==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.18.17': resolution: {integrity: sha512-QM50vJ/y+8I60qEmFxMoxIx4de03pGo2HwxdBeFd4nMh364X6TIBZ6VQ5UQmPbQWUVWHWws5MmJXlHAXvJEmpQ==} engines: {node: '>=12'} @@ -7734,6 +7908,12 @@ packages: cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.21.4': + resolution: {integrity: sha512-Td9jv782UMAFsuLZINfUpoF5mZIbAj+jv1YVtE58rFtfvoKRiKSkRGQfHTgKamLVT/fO7203bHa3wU122V/Bdg==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-x64@0.18.17': resolution: {integrity: sha512-/jGlhWR7Sj9JPZHzXyyMZ1RFMkNPjC6QIAan0sDOtIo2TYk3tZn5UDrkE0XgsTQCxWTTOcMPf9p6Rh2hXtl5TQ==} engines: {node: '>=12'} @@ -7758,6 +7938,12 @@ packages: cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.21.4': + resolution: {integrity: sha512-Awn38oSXxsPMQxaV0Ipb7W/gxZtk5Tx3+W+rAPdZkyEhQ6968r9NvtkjhnhbEgWXYbgV+JEONJ6PcdBS+nlcpA==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-x64@0.18.17': resolution: {integrity: sha512-rSEeYaGgyGGf4qZM2NonMhMOP/5EHp4u9ehFiBrg7stH6BYEEjlkVREuDEcQ0LfIl53OXLxNbfuIj7mr5m29TA==} engines: {node: '>=12'} @@ -7782,6 +7968,12 @@ packages: cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.21.4': + resolution: {integrity: sha512-IsUmQeCY0aU374R82fxIPu6vkOybWIMc3hVGZ3ChRwL9hA1TwY+tS0lgFWV5+F1+1ssuvvXt3HFqe8roCip8Hg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + '@esbuild/sunos-x64@0.18.17': resolution: {integrity: sha512-Y7ZBbkLqlSgn4+zot4KUNYst0bFoO68tRgI6mY2FIM+b7ZbyNVtNbDP5y8qlu4/knZZ73fgJDlXID+ohY5zt5g==} engines: {node: '>=12'} @@ -7806,6 +7998,12 @@ packages: cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.21.4': + resolution: {integrity: sha512-hsKhgZ4teLUaDA6FG/QIu2q0rI6I36tZVfM4DBZv3BG0mkMIdEnMbhc4xwLvLJSS22uWmaVkFkqWgIS0gPIm+A==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.18.17': resolution: {integrity: sha512-bwPmTJsEQcbZk26oYpc4c/8PvTY3J5/QK8jM19DVlEsAB41M39aWovWoHtNm78sd6ip6prilxeHosPADXtEJFw==} engines: {node: '>=12'} @@ -7830,6 +8028,12 @@ packages: cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.21.4': + resolution: {integrity: sha512-UUfMgMoXPoA/bvGUNfUBFLCh0gt9dxZYIx9W4rfJr7+hKe5jxxHmfOK8YSH4qsHLLN4Ck8JZ+v7Q5fIm1huErg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.18.17': resolution: {integrity: sha512-H/XaPtPKli2MhW+3CQueo6Ni3Avggi6hP/YvgkEe1aSaxw+AeO8MFjq8DlgfTd9Iz4Yih3QCZI6YLMoyccnPRg==} engines: {node: '>=12'} @@ -7854,6 +8058,12 @@ packages: cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.21.4': + resolution: {integrity: sha512-yIxbspZb5kGCAHWm8dexALQ9en1IYDfErzjSEq1KzXFniHv019VT3mNtTK7t8qdy4TwT6QYHI9sEZabONHg+aw==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.18.17': resolution: {integrity: sha512-fGEb8f2BSA3CW7riJVurug65ACLuQAzKq0SSqkY2b2yHHH0MzDfbLyKIGzHwOI/gkHcxM/leuSW6D5w/LMNitA==} engines: {node: '>=12'} @@ -7878,6 +8088,12 @@ packages: cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.21.4': + resolution: {integrity: sha512-sywLRD3UK/qRJt0oBwdpYLBibk7KiRfbswmWRDabuncQYSlf8aLEEUor/oP6KRz8KEG+HoiVLBhPRD5JWjS8Sg==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.4.0': resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -7954,8 +8170,8 @@ packages: '@floating-ui/core@0.3.1': resolution: {integrity: sha512-ensKY7Ub59u16qsVIFEo2hwTCqZ/r9oZZFh51ivcLGHfUwTn8l1Xzng8RJUe91H/UP8PeqeBronAGx0qmzwk2g==} - '@floating-ui/core@1.6.4': - resolution: {integrity: sha512-a4IowK4QkXl4SCWTGUR0INAfEOX3wtsYw3rKK5InQEHMGObkR8Xk44qYQD9P4r6HHw0iIfK6GUKECmY8sTkqRA==} + '@floating-ui/core@1.6.2': + resolution: {integrity: sha512-+2XpQV9LLZeanU4ZevzRnGFg2neDeKHgFLjP6YLW+tly0IvrhqT4u8enLGjLH3qeh85g19xY5rsAusfwTdn5lg==} '@floating-ui/dom@0.1.10': resolution: {integrity: sha512-4kAVoogvQm2N0XE0G6APQJuCNuErjOfPW8Ux7DFxh8+AfugWflwVJ5LDlHOwrwut7z/30NUvdtHzQ3zSip4EzQ==} @@ -8758,11 +8974,11 @@ packages: resolution: {integrity: sha512-SaNFseFPSDQlOYM9JTyYY6wauMu6qJ8eExo+jssFyb20ZaVvxKX1eTb3Gm5aW/4aWuxn6nofU+02sCk51//wdw==} engines: {node: '>=10.0.0'} - '@mantine/code-highlight@7.10.2': - resolution: {integrity: sha512-fzWUSr4Vj2s8y0k0l1FrtcBmYrOkP13lKzPbyYN76TSiACN8A5BimDQCGdd2V9CJgI4KTIPtD+F3Di3kBUPuSQ==} + '@mantine/code-highlight@7.11.1': + resolution: {integrity: sha512-1q1DNG083f1/MRzd6qmMDGB1jn6mh4UwDMc0299c4VUg4HqxjPTNZbrCB8lusBo5VkGXuOqFlFCNrP66YjhMqQ==} peerDependencies: - '@mantine/core': 7.10.2 - '@mantine/hooks': 7.10.2 + '@mantine/core': 7.11.1 + '@mantine/hooks': 7.11.1 react: ^18.2.0 react-dom: ^18.2.0 @@ -12346,6 +12562,9 @@ packages: peerDependencies: solid-js: ^1.6.12 + '@stablelib/base64@1.0.1': + resolution: {integrity: sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==} + '@stdlib/array-float32@0.0.6': resolution: {integrity: sha512-QgKT5UaE92Rv7cxfn7wBKZAlwFFHPla8eXsMFsTGt5BiL4yUy36lwinPUh4hzybZ11rw1vifS3VAPuk6JP413Q==} engines: {node: '>=0.10.0', npm: '>2.7.0'} @@ -13912,6 +14131,9 @@ packages: '@types/bcryptjs@2.4.6': resolution: {integrity: sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==} + '@types/bluebird@3.5.38': + resolution: {integrity: sha512-yR/Kxc0dd4FfwtEoLZMoqJbM/VE/W7hXn/MIjb+axcwag0iFmSPK7OBUZq1YWLynJUoWQkfUrI7T0HDqGApNSg==} + '@types/body-parser@1.19.2': resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==} @@ -13948,9 +14170,6 @@ packages: '@types/connect-history-api-fallback@1.3.5': resolution: {integrity: sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==} - '@types/connect@3.4.35': - resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==} - '@types/connect@3.4.36': resolution: {integrity: sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==} @@ -14131,6 +14350,9 @@ packages: '@types/express@4.17.17': resolution: {integrity: sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==} + '@types/express@4.17.21': + resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} + '@types/find-cache-dir@3.2.1': resolution: {integrity: sha512-frsJrz2t/CeGifcu/6uRo4b+SzAwT4NYCVPu1GN8IB9XTzrpPkGuV0tmh9mN+/L0PklAlsC3u5Fxt0ju00LXIw==} @@ -16053,6 +16275,13 @@ packages: '@babel/core': ^7.0.0 webpack: '>=2' + babel-loader@9.1.2: + resolution: {integrity: sha512-mN14niXW43tddohGl8HPu5yfQq70iUThvFL/4QzESA7GcZoC0eVOhvWdQ8+3UlSjaDE9MVtsW9mxDY07W7VpVA==} + engines: {node: '>= 14.15.0'} + peerDependencies: + '@babel/core': ^7.12.0 + webpack: '>=5' + babel-loader@9.1.3: resolution: {integrity: sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==} engines: {node: '>= 14.15.0'} @@ -16403,6 +16632,11 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + browserslist@4.23.2: + resolution: {integrity: sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + bs-logger@0.2.6: resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} engines: {node: '>= 6'} @@ -16607,8 +16841,8 @@ packages: caniuse-lite@1.0.30001589: resolution: {integrity: sha512-vNQWS6kI+q6sBlHbh71IIeC+sRwK2N3EDySc/updIGhIee2x5z00J4c1242/5/d6EpEMdOnk/m+6tuk4/tcsqg==} - caniuse-lite@1.0.30001636: - resolution: {integrity: sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==} + caniuse-lite@1.0.30001641: + resolution: {integrity: sha512-Phv5thgl67bHYo1TtMY/MurjkHhV4EDaCosezRXgZ8jzA/Ub+wjxAvbGvjoFENStinwi5kCyOYV3mi5tOGykwA==} case-sensitive-paths-webpack-plugin@2.4.0: resolution: {integrity: sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==} @@ -17519,6 +17753,12 @@ packages: peerDependencies: postcss: ^8.4.31 + css-loader@6.7.3: + resolution: {integrity: sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==} + engines: {node: '>= 12.13.0'} + peerDependencies: + webpack: ^5.0.0 + css-loader@6.8.1: resolution: {integrity: sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g==} engines: {node: '>= 12.13.0'} @@ -17601,8 +17841,8 @@ packages: cssdb@7.5.4: resolution: {integrity: sha512-fGD+J6Jlq+aurfE1VDXlLS4Pt0VtNlu2+YgfGOdMxRyl/HQ9bDiHTwSck1Yz8A97Dt/82izSK6Bp/4nVqacOsg==} - cssdb@8.0.2: - resolution: {integrity: sha512-zbOCmmbcHvr2lP+XrZSgftGMGumbosC6IM3dbxwifwPEBD70pVJaH3Ho191VBEqDg644AM7PPPVj0ZXokTjZng==} + cssdb@8.1.0: + resolution: {integrity: sha512-BQN57lfS4dYt2iL0LgyrlDbefZKEtUyrO8rbzrbGrqBk6OoyNTQLF+porY9DrpDBjLo4NEvj2IJttC7vf3x+Ew==} cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} @@ -17666,6 +17906,9 @@ packages: csstype@3.0.9: resolution: {integrity: sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw==} + csstype@3.1.1: + resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==} + csstype@3.1.2: resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} @@ -18312,6 +18555,9 @@ packages: electron-to-chromium@1.4.682: resolution: {integrity: sha512-oCglfs8yYKs9RQjJFOHonSnhikPK3y+0SvSYc/YpYJV//6rqc0/hbwd0c7vgK4vrl6y2gJAwjkhkSGWK+z4KRA==} + electron-to-chromium@1.4.823: + resolution: {integrity: sha512-4h+oPeAiGQOHFyUJOqpoEcPj/xxlicxBzOErVeYVMMmAiXUXsGpsFd0QXBMaUUbnD8hhSfLf9uw+MlsoIA7j5w==} + elegant-spinner@1.0.1: resolution: {integrity: sha512-B+ZM+RXvRqQaAmkMlO/oSe5nMUOaUnyfGYCEHoR8wrXsZR2mA0XVibsxV1bvTwxdRWah1PkQqso2EzhILGHtEQ==} engines: {node: '>=0.10.0'} @@ -18494,6 +18740,9 @@ packages: es6-error@4.1.1: resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} + es6-promise@4.2.8: + resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} + esbuild-android-64@0.14.47: resolution: {integrity: sha512-R13Bd9+tqLVFndncMHssZrPWe6/0Kpv2/dt4aA69soX4PRxlzsVpCvoJeFE8sOEoeVEiBkI0myjlkDodXlHa0g==} engines: {node: '>=12'} @@ -18668,6 +18917,11 @@ packages: engines: {node: '>=12'} hasBin: true + esbuild@0.21.4: + resolution: {integrity: sha512-sFMcNNrj+Q0ZDolrp5pDhH0nRPN9hLIM3fRPwgbLYJeSHHgnXSnbV3xYgSVuOeLWH9c73VwmEverVzupIv5xuA==} + engines: {node: '>=12'} + hasBin: true + escalade@3.1.2: resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} engines: {node: '>=6'} @@ -19372,6 +19626,9 @@ packages: fast-safe-stringify@2.1.1: resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + fast-sha256@1.3.0: + resolution: {integrity: sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==} + fast-text-encoding@1.0.6: resolution: {integrity: sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==} @@ -20066,6 +20323,11 @@ packages: resolution: {integrity: sha512-ZyqlgowMbfj2NPjxaZZ/EtsXlOch28FRXgMd64vqZWk1bT9+wvSRLYD1om9M7QfQru51zJPAT17qXm4/zd+9QA==} engines: {node: '>= 0.10'} + glob@10.3.10: + resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + glob@10.4.1: resolution: {integrity: sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==} engines: {node: '>=16 || 14 >=14.18'} @@ -20129,10 +20391,6 @@ packages: resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==} engines: {node: '>=8'} - globals@13.23.0: - resolution: {integrity: sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==} - engines: {node: '>=8'} - globals@13.24.0: resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} engines: {node: '>=8'} @@ -21455,6 +21713,10 @@ packages: resolution: {integrity: sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==} engines: {node: '>=6'} + jackspeak@2.3.6: + resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} + engines: {node: '>=14'} + jackspeak@3.4.0: resolution: {integrity: sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==} engines: {node: '>=14'} @@ -21858,6 +22120,9 @@ packages: jose@4.13.1: resolution: {integrity: sha512-MSJQC5vXco5Br38mzaQKiq9mwt7lwj2eXpgpRyQYNHYt2lq1PjkWa7DLXX0WVcQLE9HhMh3jPiufS7fhJf+CLQ==} + jose@4.15.5: + resolution: {integrity: sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==} + joycon@3.1.1: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} @@ -22115,6 +22380,10 @@ packages: resolution: {integrity: sha512-UUOZ0CVReK1QVU3rbi9bC7N5/le8ziUj0A2ef1Q0M7OPD2KvjEYizptqIxGIo6fSLYDkqBrazILS18tYuRc8gw==} engines: {node: '>=14'} + jwks-rsa@3.1.0: + resolution: {integrity: sha512-v7nqlfezb9YfHHzYII3ef2a2j1XnGeSE/bK3WfumaYCqONAIstJbrEGapz4kadScZzEt7zYCN7bucj8C0Mv/Rg==} + engines: {node: '>=14'} + jws@3.2.2: resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} @@ -24693,6 +24962,10 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-scurry@1.10.1: + resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} + engines: {node: '>=16 || 14 >=14.17'} + path-scurry@1.11.1: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} @@ -24803,6 +25076,9 @@ packages: picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + picocolors@1.0.1: + resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} @@ -25000,8 +25276,8 @@ packages: peerDependencies: postcss: ^8.4.31 - postcss-color-functional-notation@6.0.11: - resolution: {integrity: sha512-gJ+hAtAsgBF4w7eh28Pg7EA60lx7vE5xO/B/yZawaI6FYHky+5avA9YSe73nJHnAMEVFpCMeJc6Wts5g+niksg==} + postcss-color-functional-notation@6.0.14: + resolution: {integrity: sha512-dNUX+UH4dAozZ8uMHZ3CtCNYw8fyFAmqqdcyxMr7PEdM9jLXV19YscoYO0F25KqZYhmtWKQ+4tKrIZQrwzwg7A==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4.31 @@ -25042,8 +25318,8 @@ packages: peerDependencies: postcss: ^8.4.31 - postcss-custom-media@10.0.6: - resolution: {integrity: sha512-BjihQoIO4Wjqv9fQNExSJIim8UAmkhLxuJnhJsLTRFSba1y1MhxkJK5awsM//6JJ+/Tu5QUxf624RQAvKHv6SA==} + postcss-custom-media@10.0.8: + resolution: {integrity: sha512-V1KgPcmvlGdxTel4/CyQtBJEFhMVpEmRGFrnVtgfGIHj5PJX9vO36eFBxKBeJn+aCDTed70cc+98Mz3J/uVdGQ==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4.31 @@ -25060,8 +25336,8 @@ packages: peerDependencies: postcss: ^8.4.31 - postcss-custom-properties@13.3.10: - resolution: {integrity: sha512-ejaalIpl7p0k0L5ngIZ86AZGmp3m1KdeOCbSQTK4gQcB1ncaoPTHorw206+tsZRIhIDYvh5ZButEje6740YDXw==} + postcss-custom-properties@13.3.12: + resolution: {integrity: sha512-oPn/OVqONB2ZLNqN185LDyaVByELAA/u3l2CS2TS16x2j2XsmV4kd8U49+TMxmUsEU9d8fB/I10E6U7kB0L1BA==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4.31 @@ -25072,8 +25348,8 @@ packages: peerDependencies: postcss: ^8.4.31 - postcss-custom-selectors@7.1.10: - resolution: {integrity: sha512-bV/6+IExyT2J4kMzX6c+ZMlN1xDfjcC4ePr1ywKezcTgwgUn11qQN3jdzFBpo8Dk1K7vO/OYOwMb5AtJP4JZcg==} + postcss-custom-selectors@7.1.12: + resolution: {integrity: sha512-ctIoprBMJwByYMGjXG0F7IT2iMF2hnamQ+aWZETyBM0aAlyaYdVZTeUkk8RB+9h9wP+NdN3f01lfvKl2ZSqC0g==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4.31 @@ -25144,8 +25420,8 @@ packages: peerDependencies: postcss: ^8.4.31 - postcss-double-position-gradients@5.0.6: - resolution: {integrity: sha512-QJ+089FKMaqDxOhhIHsJrh4IP7h4PIHNC5jZP5PMmnfUScNu8Hji2lskqpFWCvu+5sj+2EJFyzKd13sLEWOZmQ==} + postcss-double-position-gradients@5.0.7: + resolution: {integrity: sha512-1xEhjV9u1s4l3iP5lRt1zvMjI/ya8492o9l/ivcxHhkO3nOz16moC4JpMxDUGrOs4R3hX+KWT7gKoV842cwRgg==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4.31 @@ -25243,8 +25519,8 @@ packages: peerDependencies: postcss: ^8.4.31 - postcss-lab-function@6.0.16: - resolution: {integrity: sha512-QWv0VxfjgIl8jBR/wuQcm/o31jn4P/LwzYuVKzNQoO5t7HPcU0d3RfWUiDrHN3frmSv+YYZppr3P81tKFTDyqg==} + postcss-lab-function@6.0.19: + resolution: {integrity: sha512-vwln/mgvFrotJuGV8GFhpAOu9iGf3pvTBr6dLPDmUcqVD5OsQpEFyQMAFTxSxWXGEzBj6ld4pZ/9GDfEpXvo0g==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4.31 @@ -25377,6 +25653,12 @@ packages: peerDependencies: postcss: ^8.4.31 + postcss-modules-local-by-default@4.0.0: + resolution: {integrity: sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.4.31 + postcss-modules-local-by-default@4.0.3: resolution: {integrity: sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==} engines: {node: ^10 || ^12 || >= 14} @@ -25550,8 +25832,8 @@ packages: peerDependencies: postcss: ^8.4.31 - postcss-preset-env@9.5.14: - resolution: {integrity: sha512-gTMi+3kENN/mN+K59aR+vEOjlkujTmmXJcM9rnAqGh9Y/euQ/ypdp9rd8mO1eoIjAD8vNS15+xbkBxoi+65BqQ==} + postcss-preset-env@9.6.0: + resolution: {integrity: sha512-Lxfk4RYjUdwPCYkc321QMdgtdCP34AeI94z+/8kVmqnTIlD4bMRQeGcMZgwz8BxHrzQiFXYIR5d7k/9JMs2MEA==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.4.31 @@ -27218,8 +27500,8 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true - rrdom@2.0.0-alpha.15: - resolution: {integrity: sha512-c7BMmqJf6u9cm5G1wx7Mgnc5pyNog4CLaGTDUZCDGZAIfRIFOWwu7A4f2z9IPiEeokgc5wq8R/8/dKp6xpg8Ug==} + rrdom@2.0.0-alpha.16: + resolution: {integrity: sha512-m8aoeORWUz7AFdEb7hES7wPeL6fl/oP23RoAlzLXyA/f2+NqCDM7KEyCXY4sHu6CChN3OAUP2BaUGEXn0zynlw==} rrule@2.7.2: resolution: {integrity: sha512-NkBsEEB6FIZOZ3T8frvEBOB243dm46SPufpDckY/Ap/YH24V1zLeMmDY8OA10lk452NdrF621+ynDThE7FQU2A==} @@ -27227,8 +27509,11 @@ packages: rrweb-cssom@0.6.0: resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==} - rrweb-snapshot@2.0.0-alpha.15: - resolution: {integrity: sha512-U5lOYoMt6YsmxKcnWVhX1ller6B8/OICQqLWqvylajTYv5oRHgAk68AFDTAXxLsjMSTQjtr1Vp+REFSmnhWrIg==} + rrweb-snapshot@2.0.0-alpha.13: + resolution: {integrity: sha512-slbhNBCYjxLGCeH95a67ECCy5a22nloXp1F5wF7DCzUNw80FN7tF9Lef1sRGLNo32g3mNqTc2sWLATlKejMxYw==} + + rrweb-snapshot@2.0.0-alpha.16: + resolution: {integrity: sha512-p81OrzUiCmUMZzJu4fGHeLB00PIbVIqsV/zhqzr2pitHTUXpMYcyOvDWt0vHdla0vnowEPaHq3Wsu6cUc732/w==} rrweb@2.0.0-alpha.13: resolution: {integrity: sha512-a8GXOCnzWHNaVZPa7hsrLZtNZ3CGjiL+YrkpLo0TfmxGLhjNZbWY2r7pE06p+FcjFNlgUVTmFrSJbK3kO7yxvw==} @@ -27716,6 +28001,13 @@ packages: snake-case@2.1.0: resolution: {integrity: sha512-FMR5YoPFwOLuh4rRz92dywJjyKYZNLpMn1R5ujVpIYkbA9p01fq8RMg0FkO4M+Yobt4MjHeLTJVm5xFFBHSV2Q==} + snake-case@3.0.4: + resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} + + snakecase-keys@5.4.4: + resolution: {integrity: sha512-YTywJG93yxwHLgrYLZjlC75moVEX04LZM4FHfihjHe1FCXm+QaLOFfSf535aXOAd0ArVQMWUAe8ZPm4VtWyXaA==} + engines: {node: '>=12'} + snapdragon-node@2.1.1: resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==} engines: {node: '>=0.10.0'} @@ -28401,6 +28693,12 @@ packages: engines: {node: '>=10.13.0'} hasBin: true + svix-fetch@3.0.0: + resolution: {integrity: sha512-rcADxEFhSqHbraZIsjyZNh4TF6V+koloX1OzZ+AQuObX9mZ2LIMhm1buZeuc5BIZPftZpJCMBsSiBaeszo9tRw==} + + svix@1.24.0: + resolution: {integrity: sha512-TEznBskvdvEJElo/j7BiIZAoaQEWyj/NCmwiV0izlVRf5DnCBFdowkEXERDA3JgUlAYoAJi0S7atWit7nkTMtw==} + swagger-ui-dist@4.18.2: resolution: {integrity: sha512-oVBoBl9Dg+VJw8uRWDxlyUyHoNEDC0c1ysT6+Boy6CTgr2rUcLcfPon4RvxgS2/taNW6O0+US+Z/dlAsWFjOAQ==} @@ -28425,6 +28723,11 @@ packages: '@swc/core': ^1.2.147 webpack: '>=2' + swr@2.2.5: + resolution: {integrity: sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg==} + peerDependencies: + react: ^16.11.0 || ^17.0.0 || ^18.0.0 + symbol-observable@1.2.0: resolution: {integrity: sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==} engines: {node: '>=0.10.0'} @@ -29038,6 +29341,9 @@ packages: tslib@2.1.0: resolution: {integrity: sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==} + tslib@2.4.1: + resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==} + tslib@2.5.0: resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==} @@ -29466,6 +29772,12 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + update-browserslist-db@1.1.0: + resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + upper-case-first@1.1.2: resolution: {integrity: sha512-wINKYvI3Db8dtjikdAqoBbZoP6Q+PZUyfMR7pmwHzjC2quzSkUq5DmPrTtPEqHaz8AGtmsB4TqwapMTM1QAQOQ==} @@ -29699,10 +30011,6 @@ packages: resolution: {integrity: sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==} engines: {node: '>= 0.10'} - validator@13.9.0: - resolution: {integrity: sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA==} - engines: {node: '>= 0.10'} - value-or-promise@1.0.12: resolution: {integrity: sha512-Z6Uz+TYwEqE7ZN50gwn+1LCVo9ZVrpxRPOhOLnncYkY1ZzOYtrX8Fwf/rFktZ8R5mJms6EZf5TqNOMeZmnPq9Q==} engines: {node: '>=12'} @@ -30713,7 +31021,7 @@ snapshots: autoprefixer: 10.4.14(postcss@8.4.31) babel-loader: 9.1.3(@babel/core@7.22.9)(webpack@5.88.2(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.17)) babel-plugin-istanbul: 6.1.1 - browserslist: 4.23.0 + browserslist: 4.21.10 chokidar: 3.5.3 copy-webpack-plugin: 11.0.0(webpack@5.88.2(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.17)) critters: 0.0.20 @@ -31413,7 +31721,7 @@ snapshots: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sso-oidc': 3.575.0 - '@aws-sdk/client-sts': 3.575.0 + '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) '@aws-sdk/core': 3.575.0 '@aws-sdk/credential-provider-node': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0) '@aws-sdk/middleware-bucket-endpoint': 3.575.0 @@ -31643,7 +31951,7 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.575.0 + '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) '@aws-sdk/core': 3.575.0 '@aws-sdk/credential-provider-node': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0) '@aws-sdk/middleware-host-header': 3.575.0 @@ -31976,58 +32284,13 @@ snapshots: - aws-crt optional: true - '@aws-sdk/client-sts@3.575.0': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.575.0 - '@aws-sdk/core': 3.575.0 - '@aws-sdk/credential-provider-node': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0) - '@aws-sdk/middleware-host-header': 3.575.0 - '@aws-sdk/middleware-logger': 3.575.0 - '@aws-sdk/middleware-recursion-detection': 3.575.0 - '@aws-sdk/middleware-user-agent': 3.575.0 - '@aws-sdk/region-config-resolver': 3.575.0 - '@aws-sdk/types': 3.575.0 - '@aws-sdk/util-endpoints': 3.575.0 - '@aws-sdk/util-user-agent-browser': 3.575.0 - '@aws-sdk/util-user-agent-node': 3.575.0 - '@smithy/config-resolver': 3.0.0 - '@smithy/core': 2.0.0 - '@smithy/fetch-http-handler': 3.0.0 - '@smithy/hash-node': 3.0.0 - '@smithy/invalid-dependency': 3.0.0 - '@smithy/middleware-content-length': 3.0.0 - '@smithy/middleware-endpoint': 3.0.0 - '@smithy/middleware-retry': 3.0.0 - '@smithy/middleware-serde': 3.0.0 - '@smithy/middleware-stack': 3.0.0 - '@smithy/node-config-provider': 3.0.0 - '@smithy/node-http-handler': 3.0.0 - '@smithy/protocol-http': 4.0.0 - '@smithy/smithy-client': 3.0.0 - '@smithy/types': 3.0.0 - '@smithy/url-parser': 3.0.0 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.0 - '@smithy/util-defaults-mode-node': 3.0.0 - '@smithy/util-endpoints': 2.0.0 - '@smithy/util-middleware': 3.0.0 - '@smithy/util-retry': 3.0.0 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - '@aws-sdk/client-sts@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sso-oidc': 3.575.0 '@aws-sdk/core': 3.575.0 - '@aws-sdk/credential-provider-node': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)) + '@aws-sdk/credential-provider-node': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0) '@aws-sdk/middleware-host-header': 3.575.0 '@aws-sdk/middleware-logger': 3.575.0 '@aws-sdk/middleware-recursion-detection': 3.575.0 @@ -32200,26 +32463,9 @@ snapshots: - aws-crt optional: true - '@aws-sdk/credential-provider-ini@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0(@aws-sdk/client-sso-oidc@3.575.0))': - dependencies: - '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) - '@aws-sdk/credential-provider-env': 3.575.0 - '@aws-sdk/credential-provider-process': 3.575.0 - '@aws-sdk/credential-provider-sso': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) - '@aws-sdk/credential-provider-web-identity': 3.575.0(@aws-sdk/client-sts@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)) - '@aws-sdk/types': 3.575.0 - '@smithy/credential-provider-imds': 3.0.0 - '@smithy/property-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt - '@aws-sdk/credential-provider-ini@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0)': dependencies: - '@aws-sdk/client-sts': 3.575.0 + '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) '@aws-sdk/credential-provider-env': 3.575.0 '@aws-sdk/credential-provider-process': 3.575.0 '@aws-sdk/credential-provider-sso': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) @@ -32284,25 +32530,6 @@ snapshots: - aws-crt optional: true - '@aws-sdk/credential-provider-node@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0(@aws-sdk/client-sso-oidc@3.575.0))': - dependencies: - '@aws-sdk/credential-provider-env': 3.575.0 - '@aws-sdk/credential-provider-http': 3.575.0 - '@aws-sdk/credential-provider-ini': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)) - '@aws-sdk/credential-provider-process': 3.575.0 - '@aws-sdk/credential-provider-sso': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) - '@aws-sdk/credential-provider-web-identity': 3.575.0(@aws-sdk/client-sts@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)) - '@aws-sdk/types': 3.575.0 - '@smithy/credential-provider-imds': 3.0.0 - '@smithy/property-provider': 3.0.0 - '@smithy/shared-ini-file-loader': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - '@aws-sdk/client-sts' - - aws-crt - '@aws-sdk/credential-provider-node@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0)': dependencies: '@aws-sdk/credential-provider-env': 3.575.0 @@ -32432,17 +32659,9 @@ snapshots: - aws-crt optional: true - '@aws-sdk/credential-provider-web-identity@3.575.0(@aws-sdk/client-sts@3.575.0(@aws-sdk/client-sso-oidc@3.575.0))': - dependencies: - '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) - '@aws-sdk/types': 3.575.0 - '@smithy/property-provider': 3.0.0 - '@smithy/types': 3.0.0 - tslib: 2.6.2 - '@aws-sdk/credential-provider-web-identity@3.575.0(@aws-sdk/client-sts@3.575.0)': dependencies: - '@aws-sdk/client-sts': 3.575.0 + '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) '@aws-sdk/types': 3.575.0 '@smithy/property-provider': 3.0.0 '@smithy/types': 3.0.0 @@ -33227,16 +33446,16 @@ snapshots: '@babel/core@7.22.9': dependencies: - '@ampproject/remapping': 2.3.0 + '@ampproject/remapping': 2.2.1 '@babel/code-frame': 7.24.7 - '@babel/generator': 7.24.4 + '@babel/generator': 7.23.0 '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.22.9) - '@babel/helpers': 7.24.4 - '@babel/parser': 7.24.4 - '@babel/template': 7.24.0 - '@babel/traverse': 7.24.1 - '@babel/types': 7.24.5 + '@babel/helper-module-transforms': 7.23.0(@babel/core@7.22.9) + '@babel/helpers': 7.23.2 + '@babel/parser': 7.23.0 + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.2 + '@babel/types': 7.24.0 convert-source-map: 1.9.0 debug: 4.3.5(supports-color@8.1.1) gensync: 1.0.0-beta.2 @@ -33267,8 +33486,8 @@ snapshots: '@babel/core@7.24.4': dependencies: - '@ampproject/remapping': 2.2.1 - '@babel/code-frame': 7.24.2 + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.24.7 '@babel/generator': 7.24.4 '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.4) @@ -33295,7 +33514,7 @@ snapshots: '@babel/generator@7.22.9': dependencies: - '@babel/types': 7.24.5 + '@babel/types': 7.24.0 '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 jsesc: 2.5.2 @@ -33320,7 +33539,7 @@ snapshots: '@babel/helper-annotate-as-pure@7.22.5': dependencies: - '@babel/types': 7.24.5 + '@babel/types': 7.24.0 '@babel/helper-builder-binary-assignment-operator-visitor@7.22.15': dependencies: @@ -33352,7 +33571,7 @@ snapshots: '@babel/helper-optimise-call-expression': 7.22.5 '@babel/helper-replace-supers': 7.22.20(@babel/core@7.21.4) '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/helper-split-export-declaration': 7.24.5 + '@babel/helper-split-export-declaration': 7.22.6 semver: 6.3.1 '@babel/helper-create-class-features-plugin@7.22.15(@babel/core@7.22.11)': @@ -33365,33 +33584,33 @@ snapshots: '@babel/helper-optimise-call-expression': 7.22.5 '@babel/helper-replace-supers': 7.22.20(@babel/core@7.22.11) '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/helper-split-export-declaration': 7.24.5 + '@babel/helper-split-export-declaration': 7.22.6 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.22.15(@babel/core@7.24.4)': + '@babel/helper-create-class-features-plugin@7.22.15(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-function-name': 7.23.0 '@babel/helper-member-expression-to-functions': 7.22.15 '@babel/helper-optimise-call-expression': 7.22.5 - '@babel/helper-replace-supers': 7.22.20(@babel/core@7.24.4) + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.22.9) '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/helper-split-export-declaration': 7.24.5 + '@babel/helper-split-export-declaration': 7.22.6 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.24.5(@babel/core@7.22.9)': + '@babel/helper-create-class-features-plugin@7.22.15(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 + '@babel/core': 7.24.4 '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-function-name': 7.23.0 - '@babel/helper-member-expression-to-functions': 7.24.5 + '@babel/helper-member-expression-to-functions': 7.22.15 '@babel/helper-optimise-call-expression': 7.22.5 - '@babel/helper-replace-supers': 7.24.1(@babel/core@7.22.9) + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.24.4) '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/helper-split-export-declaration': 7.24.5 + '@babel/helper-split-export-declaration': 7.22.6 semver: 6.3.1 '@babel/helper-create-class-features-plugin@7.24.5(@babel/core@7.24.4)': @@ -33461,22 +33680,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.22.9)': - dependencies: - '@babel/core': 7.22.9 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.24.7 - debug: 4.3.5(supports-color@8.1.1) - lodash.debounce: 4.0.8 - resolve: 1.22.8 - transitivePeerDependencies: - - supports-color - '@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 debug: 4.3.5(supports-color@8.1.1) lodash.debounce: 4.0.8 resolve: 1.22.8 @@ -33524,7 +33732,7 @@ snapshots: '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-module-imports': 7.24.3 '@babel/helper-simple-access': 7.22.5 - '@babel/helper-split-export-declaration': 7.24.5 + '@babel/helper-split-export-declaration': 7.22.6 '@babel/helper-validator-identifier': 7.24.7 '@babel/helper-module-transforms@7.22.20(@babel/core@7.22.11)': @@ -33533,7 +33741,7 @@ snapshots: '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-module-imports': 7.24.3 '@babel/helper-simple-access': 7.22.5 - '@babel/helper-split-export-declaration': 7.24.5 + '@babel/helper-split-export-declaration': 7.22.6 '@babel/helper-validator-identifier': 7.24.7 '@babel/helper-module-transforms@7.22.20(@babel/core@7.24.4)': @@ -33542,7 +33750,16 @@ snapshots: '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-module-imports': 7.24.3 '@babel/helper-simple-access': 7.22.5 - '@babel/helper-split-export-declaration': 7.24.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.24.7 + + '@babel/helper-module-transforms@7.23.0(@babel/core@7.22.9)': + dependencies: + '@babel/core': 7.22.9 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.24.3 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 '@babel/helper-validator-identifier': 7.24.7 '@babel/helper-module-transforms@7.23.0(@babel/core@7.23.2)': @@ -33551,7 +33768,7 @@ snapshots: '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-module-imports': 7.24.3 '@babel/helper-simple-access': 7.22.5 - '@babel/helper-split-export-declaration': 7.24.5 + '@babel/helper-split-export-declaration': 7.22.6 '@babel/helper-validator-identifier': 7.24.7 '@babel/helper-module-transforms@7.23.3(@babel/core@7.22.11)': @@ -33628,18 +33845,18 @@ snapshots: '@babel/helper-member-expression-to-functions': 7.22.15 '@babel/helper-optimise-call-expression': 7.22.5 - '@babel/helper-replace-supers@7.22.20(@babel/core@7.24.4)': + '@babel/helper-replace-supers@7.22.20(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-member-expression-to-functions': 7.22.15 '@babel/helper-optimise-call-expression': 7.22.5 - '@babel/helper-replace-supers@7.24.1(@babel/core@7.22.9)': + '@babel/helper-replace-supers@7.22.20(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 + '@babel/core': 7.24.4 '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-member-expression-to-functions': 7.24.5 + '@babel/helper-member-expression-to-functions': 7.22.15 '@babel/helper-optimise-call-expression': 7.22.5 '@babel/helper-replace-supers@7.24.1(@babel/core@7.24.4)': @@ -33659,7 +33876,7 @@ snapshots: '@babel/helper-split-export-declaration@7.22.6': dependencies: - '@babel/types': 7.24.5 + '@babel/types': 7.24.0 '@babel/helper-split-export-declaration@7.24.5': dependencies: @@ -33738,27 +33955,27 @@ snapshots: dependencies: '@babel/core': 7.24.4 '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.22.15(@babel/core@7.22.11)': dependencies: '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.22.15(@babel/core@7.24.4)': + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.22.15(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.1(@babel/core@7.22.9)': + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.22.15(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.22.15(@babel/core@7.22.11)': dependencies: @@ -33767,24 +33984,24 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-transform-optional-chaining': 7.23.0(@babel/core@7.22.11) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.22.15(@babel/core@7.24.4)': + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.22.15(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-plugin-utils': 7.22.5 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-transform-optional-chaining': 7.23.0(@babel/core@7.24.4) + '@babel/plugin-transform-optional-chaining': 7.23.0(@babel/core@7.22.9) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.1(@babel/core@7.22.9)': + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.22.15(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-transform-optional-chaining': 7.24.5(@babel/core@7.22.9) + '@babel/plugin-transform-optional-chaining': 7.23.0(@babel/core@7.24.4) '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-transform-optional-chaining': 7.24.5(@babel/core@7.24.4) @@ -33792,13 +34009,13 @@ snapshots: dependencies: '@babel/core': 7.24.4 '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.22.9)': dependencies: '@babel/core': 7.22.9 '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.22.5 '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.22.9) '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.9) @@ -33873,7 +34090,7 @@ snapshots: dependencies: '@babel/core': 7.22.9 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.22.9) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.21.4)': dependencies: @@ -33898,12 +34115,12 @@ snapshots: '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.21.4)': dependencies: '@babel/core': 7.21.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.21.4)': dependencies: @@ -33978,57 +34195,57 @@ snapshots: '@babel/plugin-syntax-flow@7.22.5(@babel/core@7.22.11)': dependencies: '@babel/core': 7.22.11 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-syntax-flow@7.22.5(@babel/core@7.23.2)': dependencies: '@babel/core': 7.23.2 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-syntax-flow@7.22.5(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-syntax-import-assertions@7.22.5(@babel/core@7.22.11)': dependencies: '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-import-assertions@7.22.5(@babel/core@7.24.4)': + '@babel/plugin-syntax-import-assertions@7.22.5(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-import-assertions@7.24.1(@babel/core@7.22.9)': + '@babel/plugin-syntax-import-assertions@7.22.5(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-import-assertions@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-syntax-import-attributes@7.22.5(@babel/core@7.22.11)': dependencies: '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-import-attributes@7.22.5(@babel/core@7.24.4)': + '@babel/plugin-syntax-import-attributes@7.22.5(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-import-attributes@7.24.1(@babel/core@7.22.9)': + '@babel/plugin-syntax-import-attributes@7.22.5(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-import-attributes@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.21.4)': dependencies: @@ -34293,20 +34510,20 @@ snapshots: '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-arrow-functions@7.22.5(@babel/core@7.24.4)': + '@babel/plugin-transform-arrow-functions@7.22.5(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-arrow-functions@7.24.1(@babel/core@7.22.9)': + '@babel/plugin-transform-arrow-functions@7.22.5(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-transform-arrow-functions@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-transform-async-generator-functions@7.23.2(@babel/core@7.22.11)': dependencies: @@ -34316,6 +34533,14 @@ snapshots: '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.22.11) '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.11) + '@babel/plugin-transform-async-generator-functions@7.23.2(@babel/core@7.22.9)': + dependencies: + '@babel/core': 7.22.9 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.22.9) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.9) + '@babel/plugin-transform-async-generator-functions@7.23.2(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 @@ -34324,19 +34549,11 @@ snapshots: '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.4) '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.4) - '@babel/plugin-transform-async-generator-functions@7.24.3(@babel/core@7.22.9)': - dependencies: - '@babel/core': 7.22.9 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-plugin-utils': 7.24.7 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.22.9) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.9) - '@babel/plugin-transform-async-generator-functions@7.24.3(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.4) '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.4) @@ -34361,18 +34578,11 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.4) - '@babel/plugin-transform-async-to-generator@7.24.1(@babel/core@7.22.9)': - dependencies: - '@babel/core': 7.22.9 - '@babel/helper-module-imports': 7.24.3 - '@babel/helper-plugin-utils': 7.24.7 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.22.9) - '@babel/plugin-transform-async-to-generator@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-module-imports': 7.24.3 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.4) '@babel/plugin-transform-block-scoped-functions@7.22.5(@babel/core@7.22.11)': @@ -34380,40 +34590,40 @@ snapshots: '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-block-scoped-functions@7.22.5(@babel/core@7.24.4)': + '@babel/plugin-transform-block-scoped-functions@7.22.5(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-block-scoped-functions@7.24.1(@babel/core@7.22.9)': + '@babel/plugin-transform-block-scoped-functions@7.22.5(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-transform-block-scoped-functions@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-transform-block-scoping@7.23.0(@babel/core@7.22.11)': dependencies: '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-block-scoping@7.23.0(@babel/core@7.24.4)': + '@babel/plugin-transform-block-scoping@7.23.0(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-block-scoping@7.24.5(@babel/core@7.22.9)': + '@babel/plugin-transform-block-scoping@7.23.0(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-transform-block-scoping@7.24.5(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-transform-class-properties@7.22.5(@babel/core@7.22.11)': dependencies: @@ -34421,23 +34631,23 @@ snapshots: '@babel/helper-create-class-features-plugin': 7.22.15(@babel/core@7.22.11) '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-class-properties@7.22.5(@babel/core@7.22.9)': + dependencies: + '@babel/core': 7.22.9 + '@babel/helper-create-class-features-plugin': 7.22.15(@babel/core@7.22.9) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-class-properties@7.22.5(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-create-class-features-plugin': 7.22.15(@babel/core@7.24.4) '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-class-properties@7.24.1(@babel/core@7.22.9)': - dependencies: - '@babel/core': 7.22.9 - '@babel/helper-create-class-features-plugin': 7.24.5(@babel/core@7.22.9) - '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-class-properties@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-create-class-features-plugin': 7.24.5(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-transform-class-static-block@7.22.11(@babel/core@7.22.11)': dependencies: @@ -34446,6 +34656,13 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.22.11) + '@babel/plugin-transform-class-static-block@7.22.11(@babel/core@7.22.9)': + dependencies: + '@babel/core': 7.22.9 + '@babel/helper-create-class-features-plugin': 7.22.15(@babel/core@7.22.9) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.22.9) + '@babel/plugin-transform-class-static-block@7.22.11(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 @@ -34453,18 +34670,11 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.4) - '@babel/plugin-transform-class-static-block@7.24.4(@babel/core@7.22.9)': - dependencies: - '@babel/core': 7.22.9 - '@babel/helper-create-class-features-plugin': 7.24.5(@babel/core@7.22.9) - '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.22.9) - '@babel/plugin-transform-class-static-block@7.24.4(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-create-class-features-plugin': 7.24.5(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.4) '@babel/plugin-transform-classes@7.22.15(@babel/core@7.22.11)': @@ -34480,29 +34690,30 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 globals: 11.12.0 - '@babel/plugin-transform-classes@7.22.15(@babel/core@7.24.4)': + '@babel/plugin-transform-classes@7.22.15(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-function-name': 7.23.0 '@babel/helper-optimise-call-expression': 7.22.5 '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-replace-supers': 7.22.20(@babel/core@7.24.4) + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.22.9) '@babel/helper-split-export-declaration': 7.22.6 globals: 11.12.0 - '@babel/plugin-transform-classes@7.24.5(@babel/core@7.22.9)': + '@babel/plugin-transform-classes@7.22.15(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 + '@babel/core': 7.24.4 '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-function-name': 7.23.0 - '@babel/helper-plugin-utils': 7.24.7 - '@babel/helper-replace-supers': 7.24.1(@babel/core@7.22.9) - '@babel/helper-split-export-declaration': 7.24.5 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.24.4) + '@babel/helper-split-export-declaration': 7.22.6 globals: 11.12.0 '@babel/plugin-transform-classes@7.24.5(@babel/core@7.24.4)': @@ -34512,7 +34723,7 @@ snapshots: '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-function-name': 7.23.0 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/helper-replace-supers': 7.24.1(@babel/core@7.24.4) '@babel/helper-split-export-declaration': 7.24.5 globals: 11.12.0 @@ -34523,22 +34734,22 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/template': 7.22.15 - '@babel/plugin-transform-computed-properties@7.22.5(@babel/core@7.24.4)': + '@babel/plugin-transform-computed-properties@7.22.5(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-plugin-utils': 7.22.5 '@babel/template': 7.22.15 - '@babel/plugin-transform-computed-properties@7.24.1(@babel/core@7.22.9)': + '@babel/plugin-transform-computed-properties@7.22.5(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 - '@babel/template': 7.24.0 + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/template': 7.22.15 '@babel/plugin-transform-computed-properties@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/template': 7.24.0 '@babel/plugin-transform-destructuring@7.23.0(@babel/core@7.22.11)': @@ -34546,20 +34757,20 @@ snapshots: '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-destructuring@7.23.0(@babel/core@7.24.4)': + '@babel/plugin-transform-destructuring@7.23.0(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-destructuring@7.24.5(@babel/core@7.22.9)': + '@babel/plugin-transform-destructuring@7.23.0(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-transform-destructuring@7.24.5(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-transform-dotall-regex@7.22.5(@babel/core@7.22.11)': dependencies: @@ -34567,43 +34778,43 @@ snapshots: '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.22.11) '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-dotall-regex@7.22.5(@babel/core@7.22.9)': + dependencies: + '@babel/core': 7.22.9 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.22.9) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-dotall-regex@7.22.5(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.4) '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-dotall-regex@7.24.1(@babel/core@7.22.9)': - dependencies: - '@babel/core': 7.22.9 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.22.9) - '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-dotall-regex@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-transform-duplicate-keys@7.22.5(@babel/core@7.22.11)': dependencies: '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-duplicate-keys@7.22.5(@babel/core@7.24.4)': + '@babel/plugin-transform-duplicate-keys@7.22.5(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-duplicate-keys@7.24.1(@babel/core@7.22.9)': + '@babel/plugin-transform-duplicate-keys@7.22.5(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-transform-duplicate-keys@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-transform-dynamic-import@7.22.11(@babel/core@7.22.11)': dependencies: @@ -34611,22 +34822,22 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.22.11) + '@babel/plugin-transform-dynamic-import@7.22.11(@babel/core@7.22.9)': + dependencies: + '@babel/core': 7.22.9 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.22.9) + '@babel/plugin-transform-dynamic-import@7.22.11(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.4) - '@babel/plugin-transform-dynamic-import@7.24.1(@babel/core@7.22.9)': - dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.22.9) - '@babel/plugin-transform-dynamic-import@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.4) '@babel/plugin-transform-exponentiation-operator@7.22.5(@babel/core@7.22.11)': @@ -34635,23 +34846,23 @@ snapshots: '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-exponentiation-operator@7.22.5(@babel/core@7.24.4)': + '@babel/plugin-transform-exponentiation-operator@7.22.5(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-exponentiation-operator@7.24.1(@babel/core@7.22.9)': + '@babel/plugin-transform-exponentiation-operator@7.22.5(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 + '@babel/core': 7.24.4 '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-transform-exponentiation-operator@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-transform-export-namespace-from@7.22.11(@babel/core@7.22.11)': dependencies: @@ -34659,22 +34870,22 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.22.11) + '@babel/plugin-transform-export-namespace-from@7.22.11(@babel/core@7.22.9)': + dependencies: + '@babel/core': 7.22.9 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.22.9) + '@babel/plugin-transform-export-namespace-from@7.22.11(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.4) - '@babel/plugin-transform-export-namespace-from@7.24.1(@babel/core@7.22.9)': - dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.22.9) - '@babel/plugin-transform-export-namespace-from@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.4) '@babel/plugin-transform-flow-strip-types@7.22.5(@babel/core@7.22.11)': @@ -34700,21 +34911,20 @@ snapshots: '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-for-of@7.22.15(@babel/core@7.24.4)': + '@babel/plugin-transform-for-of@7.22.15(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-for-of@7.24.1(@babel/core@7.22.9)': + '@babel/plugin-transform-for-of@7.22.15(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-transform-for-of@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-transform-function-name@7.22.5(@babel/core@7.22.11)': @@ -34724,26 +34934,26 @@ snapshots: '@babel/helper-function-name': 7.23.0 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-function-name@7.22.5(@babel/core@7.24.4)': + '@babel/plugin-transform-function-name@7.22.5(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-function-name': 7.23.0 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-function-name@7.24.1(@babel/core@7.22.9)': + '@babel/plugin-transform-function-name@7.22.5(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 + '@babel/core': 7.24.4 '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-function-name': 7.23.0 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-transform-function-name@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-function-name': 7.23.0 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-transform-json-strings@7.22.11(@babel/core@7.22.11)': dependencies: @@ -34751,22 +34961,22 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.22.11) + '@babel/plugin-transform-json-strings@7.22.11(@babel/core@7.22.9)': + dependencies: + '@babel/core': 7.22.9 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.22.9) + '@babel/plugin-transform-json-strings@7.22.11(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.4) - '@babel/plugin-transform-json-strings@7.24.1(@babel/core@7.22.9)': - dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.22.9) - '@babel/plugin-transform-json-strings@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.4) '@babel/plugin-transform-literals@7.22.5(@babel/core@7.22.11)': @@ -34774,20 +34984,20 @@ snapshots: '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-literals@7.22.5(@babel/core@7.24.4)': + '@babel/plugin-transform-literals@7.22.5(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-literals@7.24.1(@babel/core@7.22.9)': + '@babel/plugin-transform-literals@7.22.5(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-transform-literals@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-transform-logical-assignment-operators@7.22.11(@babel/core@7.22.11)': dependencies: @@ -34795,22 +35005,22 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.22.11) + '@babel/plugin-transform-logical-assignment-operators@7.22.11(@babel/core@7.22.9)': + dependencies: + '@babel/core': 7.22.9 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.22.9) + '@babel/plugin-transform-logical-assignment-operators@7.22.11(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.4) - '@babel/plugin-transform-logical-assignment-operators@7.24.1(@babel/core@7.22.9)': - dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.22.9) - '@babel/plugin-transform-logical-assignment-operators@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.4) '@babel/plugin-transform-member-expression-literals@7.22.5(@babel/core@7.22.11)': @@ -34818,20 +35028,20 @@ snapshots: '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-member-expression-literals@7.22.5(@babel/core@7.24.4)': + '@babel/plugin-transform-member-expression-literals@7.22.5(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-member-expression-literals@7.24.1(@babel/core@7.22.9)': + '@babel/plugin-transform-member-expression-literals@7.22.5(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-transform-member-expression-literals@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-transform-modules-amd@7.23.0(@babel/core@7.22.11)': dependencies: @@ -34839,23 +35049,23 @@ snapshots: '@babel/helper-module-transforms': 7.23.3(@babel/core@7.22.11) '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-modules-amd@7.23.0(@babel/core@7.22.9)': + dependencies: + '@babel/core': 7.22.9 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.22.9) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-modules-amd@7.23.0(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.4) '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-modules-amd@7.24.1(@babel/core@7.22.9)': - dependencies: - '@babel/core': 7.22.9 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.22.9) - '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-modules-amd@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-transform-modules-commonjs@7.22.15(@babel/core@7.22.11)': dependencies: @@ -34878,25 +35088,25 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/helper-simple-access': 7.22.5 - '@babel/plugin-transform-modules-commonjs@7.23.0(@babel/core@7.24.4)': + '@babel/plugin-transform-modules-commonjs@7.23.0(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.4) + '@babel/core': 7.22.9 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.22.9) '@babel/helper-plugin-utils': 7.22.5 '@babel/helper-simple-access': 7.22.5 - '@babel/plugin-transform-modules-commonjs@7.24.1(@babel/core@7.22.9)': + '@babel/plugin-transform-modules-commonjs@7.23.0(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.22.9) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.24.4 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.4) + '@babel/helper-plugin-utils': 7.22.5 '@babel/helper-simple-access': 7.22.5 '@babel/plugin-transform-modules-commonjs@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/helper-simple-access': 7.22.5 '@babel/plugin-transform-modules-systemjs@7.23.0(@babel/core@7.22.11)': @@ -34907,28 +35117,28 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/helper-validator-identifier': 7.22.20 - '@babel/plugin-transform-modules-systemjs@7.23.0(@babel/core@7.24.4)': + '@babel/plugin-transform-modules-systemjs@7.23.0(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.4) + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.22.9) '@babel/helper-plugin-utils': 7.22.5 '@babel/helper-validator-identifier': 7.22.20 - '@babel/plugin-transform-modules-systemjs@7.24.1(@babel/core@7.22.9)': + '@babel/plugin-transform-modules-systemjs@7.23.0(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 + '@babel/core': 7.24.4 '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.22.9) - '@babel/helper-plugin-utils': 7.24.7 - '@babel/helper-validator-identifier': 7.24.7 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.4) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-validator-identifier': 7.22.20 '@babel/plugin-transform-modules-systemjs@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-hoist-variables': 7.22.5 '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/helper-validator-identifier': 7.24.7 '@babel/plugin-transform-modules-umd@7.22.5(@babel/core@7.22.11)': @@ -34937,23 +35147,23 @@ snapshots: '@babel/helper-module-transforms': 7.23.3(@babel/core@7.22.11) '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-modules-umd@7.22.5(@babel/core@7.22.9)': + dependencies: + '@babel/core': 7.22.9 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.22.9) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-modules-umd@7.22.5(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.4) '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-modules-umd@7.24.1(@babel/core@7.22.9)': - dependencies: - '@babel/core': 7.22.9 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.22.9) - '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-modules-umd@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.22.11)': dependencies: @@ -34978,20 +35188,20 @@ snapshots: '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-new-target@7.22.5(@babel/core@7.24.4)': + '@babel/plugin-transform-new-target@7.22.5(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-new-target@7.24.1(@babel/core@7.22.9)': + '@babel/plugin-transform-new-target@7.22.5(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-transform-new-target@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-transform-nullish-coalescing-operator@7.22.11(@babel/core@7.22.11)': dependencies: @@ -34999,22 +35209,22 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.22.11) + '@babel/plugin-transform-nullish-coalescing-operator@7.22.11(@babel/core@7.22.9)': + dependencies: + '@babel/core': 7.22.9 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.22.9) + '@babel/plugin-transform-nullish-coalescing-operator@7.22.11(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.4) - '@babel/plugin-transform-nullish-coalescing-operator@7.24.1(@babel/core@7.22.9)': - dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.22.9) - '@babel/plugin-transform-nullish-coalescing-operator@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.4) '@babel/plugin-transform-numeric-separator@7.22.11(@babel/core@7.22.11)': @@ -35023,22 +35233,22 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.22.11) + '@babel/plugin-transform-numeric-separator@7.22.11(@babel/core@7.22.9)': + dependencies: + '@babel/core': 7.22.9 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.22.9) + '@babel/plugin-transform-numeric-separator@7.22.11(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.4) - '@babel/plugin-transform-numeric-separator@7.24.1(@babel/core@7.22.9)': - dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.22.9) - '@babel/plugin-transform-numeric-separator@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.4) '@babel/plugin-transform-object-rest-spread@7.22.15(@babel/core@7.22.11)': @@ -35050,6 +35260,15 @@ snapshots: '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.22.11) '@babel/plugin-transform-parameters': 7.22.15(@babel/core@7.22.11) + '@babel/plugin-transform-object-rest-spread@7.22.15(@babel/core@7.22.9)': + dependencies: + '@babel/compat-data': 7.23.2 + '@babel/core': 7.22.9 + '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.22.9) + '@babel/plugin-transform-parameters': 7.22.15(@babel/core@7.22.9) + '@babel/plugin-transform-object-rest-spread@7.22.15(@babel/core@7.24.4)': dependencies: '@babel/compat-data': 7.23.2 @@ -35059,19 +35278,11 @@ snapshots: '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.4) '@babel/plugin-transform-parameters': 7.22.15(@babel/core@7.24.4) - '@babel/plugin-transform-object-rest-spread@7.24.5(@babel/core@7.22.9)': - dependencies: - '@babel/core': 7.22.9 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.22.9) - '@babel/plugin-transform-parameters': 7.24.5(@babel/core@7.22.9) - '@babel/plugin-transform-object-rest-spread@7.24.5(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.4) '@babel/plugin-transform-parameters': 7.24.5(@babel/core@7.24.4) @@ -35081,22 +35292,22 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/helper-replace-supers': 7.22.20(@babel/core@7.22.11) + '@babel/plugin-transform-object-super@7.22.5(@babel/core@7.22.9)': + dependencies: + '@babel/core': 7.22.9 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.22.9) + '@babel/plugin-transform-object-super@7.22.5(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-plugin-utils': 7.22.5 '@babel/helper-replace-supers': 7.22.20(@babel/core@7.24.4) - '@babel/plugin-transform-object-super@7.24.1(@babel/core@7.22.9)': - dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 - '@babel/helper-replace-supers': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-object-super@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/helper-replace-supers': 7.24.1(@babel/core@7.24.4) '@babel/plugin-transform-optional-catch-binding@7.22.11(@babel/core@7.22.11)': @@ -35105,22 +35316,22 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.22.11) + '@babel/plugin-transform-optional-catch-binding@7.22.11(@babel/core@7.22.9)': + dependencies: + '@babel/core': 7.22.9 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.22.9) + '@babel/plugin-transform-optional-catch-binding@7.22.11(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.4) - '@babel/plugin-transform-optional-catch-binding@7.24.1(@babel/core@7.22.9)': - dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.22.9) - '@babel/plugin-transform-optional-catch-binding@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.4) '@babel/plugin-transform-optional-chaining@7.23.0(@babel/core@7.22.11)': @@ -35130,24 +35341,24 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.11) - '@babel/plugin-transform-optional-chaining@7.23.0(@babel/core@7.24.4)': + '@babel/plugin-transform-optional-chaining@7.23.0(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-plugin-utils': 7.22.5 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.4) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.9) - '@babel/plugin-transform-optional-chaining@7.24.5(@babel/core@7.22.9)': + '@babel/plugin-transform-optional-chaining@7.23.0(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.9) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.4) '@babel/plugin-transform-optional-chaining@7.24.5(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.4) @@ -35156,20 +35367,20 @@ snapshots: '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-parameters@7.22.15(@babel/core@7.24.4)': + '@babel/plugin-transform-parameters@7.22.15(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-parameters@7.24.5(@babel/core@7.22.9)': + '@babel/plugin-transform-parameters@7.22.15(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-transform-parameters@7.24.5(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-transform-private-methods@7.22.5(@babel/core@7.22.11)': dependencies: @@ -35177,23 +35388,23 @@ snapshots: '@babel/helper-create-class-features-plugin': 7.22.15(@babel/core@7.22.11) '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-private-methods@7.22.5(@babel/core@7.22.9)': + dependencies: + '@babel/core': 7.22.9 + '@babel/helper-create-class-features-plugin': 7.22.15(@babel/core@7.22.9) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-private-methods@7.22.5(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-create-class-features-plugin': 7.22.15(@babel/core@7.24.4) '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-private-methods@7.24.1(@babel/core@7.22.9)': - dependencies: - '@babel/core': 7.22.9 - '@babel/helper-create-class-features-plugin': 7.24.5(@babel/core@7.22.9) - '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-private-methods@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-create-class-features-plugin': 7.24.5(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-transform-private-property-in-object@7.22.11(@babel/core@7.22.11)': dependencies: @@ -35203,6 +35414,14 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.22.11) + '@babel/plugin-transform-private-property-in-object@7.22.11(@babel/core@7.22.9)': + dependencies: + '@babel/core': 7.22.9 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.22.15(@babel/core@7.22.9) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.22.9) + '@babel/plugin-transform-private-property-in-object@7.22.11(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 @@ -35211,20 +35430,12 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.4) - '@babel/plugin-transform-private-property-in-object@7.24.5(@babel/core@7.22.9)': - dependencies: - '@babel/core': 7.22.9 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.24.5(@babel/core@7.22.9) - '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.22.9) - '@babel/plugin-transform-private-property-in-object@7.24.5(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-create-class-features-plugin': 7.24.5(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.4) '@babel/plugin-transform-property-literals@7.22.5(@babel/core@7.22.11)': @@ -35232,20 +35443,20 @@ snapshots: '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-property-literals@7.22.5(@babel/core@7.24.4)': + '@babel/plugin-transform-property-literals@7.22.5(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-property-literals@7.24.1(@babel/core@7.22.9)': + '@babel/plugin-transform-property-literals@7.22.5(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-transform-property-literals@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-transform-react-constant-elements@7.21.3(@babel/core@7.24.4)': dependencies: @@ -35378,22 +35589,22 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 regenerator-transform: 0.15.2 - '@babel/plugin-transform-regenerator@7.22.10(@babel/core@7.24.4)': + '@babel/plugin-transform-regenerator@7.22.10(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-plugin-utils': 7.22.5 regenerator-transform: 0.15.2 - '@babel/plugin-transform-regenerator@7.24.1(@babel/core@7.22.9)': + '@babel/plugin-transform-regenerator@7.22.10(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 regenerator-transform: 0.15.2 '@babel/plugin-transform-regenerator@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 regenerator-transform: 0.15.2 '@babel/plugin-transform-reserved-words@7.22.5(@babel/core@7.22.11)': @@ -35401,27 +35612,27 @@ snapshots: '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-reserved-words@7.22.5(@babel/core@7.24.4)': + '@babel/plugin-transform-reserved-words@7.22.5(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-reserved-words@7.24.1(@babel/core@7.22.9)': + '@babel/plugin-transform-reserved-words@7.22.5(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-transform-reserved-words@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-transform-runtime@7.22.9(@babel/core@7.22.9)': dependencies: '@babel/core': 7.22.9 - '@babel/helper-module-imports': 7.24.3 - '@babel/helper-plugin-utils': 7.24.7 - babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.22.9) + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-plugin-utils': 7.22.5 + babel-plugin-polyfill-corejs2: 0.4.6(@babel/core@7.22.9) babel-plugin-polyfill-corejs3: 0.8.5(@babel/core@7.22.9) babel-plugin-polyfill-regenerator: 0.5.3(@babel/core@7.22.9) semver: 6.3.1 @@ -35457,20 +35668,20 @@ snapshots: '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-shorthand-properties@7.22.5(@babel/core@7.24.4)': + '@babel/plugin-transform-shorthand-properties@7.22.5(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-shorthand-properties@7.24.1(@babel/core@7.22.9)': + '@babel/plugin-transform-shorthand-properties@7.22.5(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-transform-shorthand-properties@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-transform-spread@7.22.5(@babel/core@7.22.11)': dependencies: @@ -35478,22 +35689,22 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-transform-spread@7.22.5(@babel/core@7.24.4)': + '@babel/plugin-transform-spread@7.22.5(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-plugin-utils': 7.22.5 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-transform-spread@7.24.1(@babel/core@7.22.9)': + '@babel/plugin-transform-spread@7.22.5(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-transform-spread@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-transform-sticky-regex@7.22.5(@babel/core@7.22.11)': @@ -35501,60 +35712,60 @@ snapshots: '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-sticky-regex@7.22.5(@babel/core@7.24.4)': + '@babel/plugin-transform-sticky-regex@7.22.5(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-sticky-regex@7.24.1(@babel/core@7.22.9)': + '@babel/plugin-transform-sticky-regex@7.22.5(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-transform-sticky-regex@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-transform-template-literals@7.22.5(@babel/core@7.22.11)': dependencies: '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-template-literals@7.22.5(@babel/core@7.24.4)': + '@babel/plugin-transform-template-literals@7.22.5(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-template-literals@7.24.1(@babel/core@7.22.9)': + '@babel/plugin-transform-template-literals@7.22.5(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-transform-template-literals@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-transform-typeof-symbol@7.22.5(@babel/core@7.22.11)': dependencies: '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-typeof-symbol@7.22.5(@babel/core@7.24.4)': + '@babel/plugin-transform-typeof-symbol@7.22.5(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-typeof-symbol@7.24.5(@babel/core@7.22.9)': + '@babel/plugin-transform-typeof-symbol@7.22.5(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-transform-typeof-symbol@7.24.5(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-transform-typescript@7.21.3(@babel/core@7.21.4)': dependencies: @@ -35593,20 +35804,20 @@ snapshots: '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-unicode-escapes@7.22.10(@babel/core@7.24.4)': + '@babel/plugin-transform-unicode-escapes@7.22.10(@babel/core@7.22.9)': dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.22.9 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-unicode-escapes@7.24.1(@babel/core@7.22.9)': + '@babel/plugin-transform-unicode-escapes@7.22.10(@babel/core@7.24.4)': dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-transform-unicode-escapes@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-transform-unicode-property-regex@7.22.5(@babel/core@7.22.11)': dependencies: @@ -35614,23 +35825,23 @@ snapshots: '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.22.11) '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-unicode-property-regex@7.22.5(@babel/core@7.22.9)': + dependencies: + '@babel/core': 7.22.9 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.22.9) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-unicode-property-regex@7.22.5(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.4) '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-unicode-property-regex@7.24.1(@babel/core@7.22.9)': - dependencies: - '@babel/core': 7.22.9 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.22.9) - '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-unicode-property-regex@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-transform-unicode-regex@7.22.5(@babel/core@7.22.11)': dependencies: @@ -35638,23 +35849,23 @@ snapshots: '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.22.11) '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-unicode-regex@7.22.5(@babel/core@7.22.9)': + dependencies: + '@babel/core': 7.22.9 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.22.9) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-unicode-regex@7.22.5(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.4) '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-unicode-regex@7.24.1(@babel/core@7.22.9)': - dependencies: - '@babel/core': 7.22.9 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.22.9) - '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-unicode-regex@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-transform-unicode-sets-regex@7.22.5(@babel/core@7.22.11)': dependencies: @@ -35662,23 +35873,23 @@ snapshots: '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.22.11) '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-unicode-sets-regex@7.22.5(@babel/core@7.22.9)': + dependencies: + '@babel/core': 7.22.9 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.22.9) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-unicode-sets-regex@7.22.5(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.4) '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-unicode-sets-regex@7.24.1(@babel/core@7.22.9)': - dependencies: - '@babel/core': 7.22.9 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.22.9) - '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-unicode-sets-regex@7.24.1(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.4) - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/polyfill@7.12.1': dependencies: @@ -35690,18 +35901,18 @@ snapshots: '@babel/compat-data': 7.24.4 '@babel/core': 7.22.9 '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.22.5 '@babel/helper-validator-option': 7.23.5 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.24.1(@babel/core@7.22.9) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.22.15(@babel/core@7.22.9) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.22.15(@babel/core@7.22.9) '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.22.9) '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.9) '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.22.9) '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.22.9) '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.22.9) '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.22.9) - '@babel/plugin-syntax-import-assertions': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-syntax-import-attributes': 7.24.1(@babel/core@7.22.9) + '@babel/plugin-syntax-import-assertions': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-syntax-import-attributes': 7.22.5(@babel/core@7.22.9) '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.22.9) '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.22.9) '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.22.9) @@ -35713,60 +35924,60 @@ snapshots: '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.22.9) '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.22.9) '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.22.9) - '@babel/plugin-transform-arrow-functions': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-async-generator-functions': 7.24.3(@babel/core@7.22.9) - '@babel/plugin-transform-async-to-generator': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-block-scoped-functions': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-block-scoping': 7.24.5(@babel/core@7.22.9) - '@babel/plugin-transform-class-properties': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-class-static-block': 7.24.4(@babel/core@7.22.9) - '@babel/plugin-transform-classes': 7.24.5(@babel/core@7.22.9) - '@babel/plugin-transform-computed-properties': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-destructuring': 7.24.5(@babel/core@7.22.9) - '@babel/plugin-transform-dotall-regex': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-duplicate-keys': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-dynamic-import': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-exponentiation-operator': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-export-namespace-from': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-for-of': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-function-name': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-json-strings': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-literals': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-logical-assignment-operators': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-member-expression-literals': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-modules-amd': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-modules-commonjs': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-modules-systemjs': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-modules-umd': 7.24.1(@babel/core@7.22.9) + '@babel/plugin-transform-arrow-functions': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-async-generator-functions': 7.23.2(@babel/core@7.22.9) + '@babel/plugin-transform-async-to-generator': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-block-scoped-functions': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-block-scoping': 7.23.0(@babel/core@7.22.9) + '@babel/plugin-transform-class-properties': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-class-static-block': 7.22.11(@babel/core@7.22.9) + '@babel/plugin-transform-classes': 7.22.15(@babel/core@7.22.9) + '@babel/plugin-transform-computed-properties': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-destructuring': 7.23.0(@babel/core@7.22.9) + '@babel/plugin-transform-dotall-regex': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-duplicate-keys': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-dynamic-import': 7.22.11(@babel/core@7.22.9) + '@babel/plugin-transform-exponentiation-operator': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-export-namespace-from': 7.22.11(@babel/core@7.22.9) + '@babel/plugin-transform-for-of': 7.22.15(@babel/core@7.22.9) + '@babel/plugin-transform-function-name': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-json-strings': 7.22.11(@babel/core@7.22.9) + '@babel/plugin-transform-literals': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-logical-assignment-operators': 7.22.11(@babel/core@7.22.9) + '@babel/plugin-transform-member-expression-literals': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-modules-amd': 7.23.0(@babel/core@7.22.9) + '@babel/plugin-transform-modules-commonjs': 7.23.0(@babel/core@7.22.9) + '@babel/plugin-transform-modules-systemjs': 7.23.0(@babel/core@7.22.9) + '@babel/plugin-transform-modules-umd': 7.22.5(@babel/core@7.22.9) '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.22.9) - '@babel/plugin-transform-new-target': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-nullish-coalescing-operator': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-numeric-separator': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-object-rest-spread': 7.24.5(@babel/core@7.22.9) - '@babel/plugin-transform-object-super': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-optional-catch-binding': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-optional-chaining': 7.24.5(@babel/core@7.22.9) - '@babel/plugin-transform-parameters': 7.24.5(@babel/core@7.22.9) - '@babel/plugin-transform-private-methods': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-private-property-in-object': 7.24.5(@babel/core@7.22.9) - '@babel/plugin-transform-property-literals': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-regenerator': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-reserved-words': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-shorthand-properties': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-spread': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-sticky-regex': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-template-literals': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-typeof-symbol': 7.24.5(@babel/core@7.22.9) - '@babel/plugin-transform-unicode-escapes': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-unicode-property-regex': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-unicode-regex': 7.24.1(@babel/core@7.22.9) - '@babel/plugin-transform-unicode-sets-regex': 7.24.1(@babel/core@7.22.9) + '@babel/plugin-transform-new-target': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-nullish-coalescing-operator': 7.22.11(@babel/core@7.22.9) + '@babel/plugin-transform-numeric-separator': 7.22.11(@babel/core@7.22.9) + '@babel/plugin-transform-object-rest-spread': 7.22.15(@babel/core@7.22.9) + '@babel/plugin-transform-object-super': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-optional-catch-binding': 7.22.11(@babel/core@7.22.9) + '@babel/plugin-transform-optional-chaining': 7.23.0(@babel/core@7.22.9) + '@babel/plugin-transform-parameters': 7.22.15(@babel/core@7.22.9) + '@babel/plugin-transform-private-methods': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-private-property-in-object': 7.22.11(@babel/core@7.22.9) + '@babel/plugin-transform-property-literals': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-regenerator': 7.22.10(@babel/core@7.22.9) + '@babel/plugin-transform-reserved-words': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-shorthand-properties': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-spread': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-sticky-regex': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-template-literals': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-typeof-symbol': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-unicode-escapes': 7.22.10(@babel/core@7.22.9) + '@babel/plugin-transform-unicode-property-regex': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-unicode-regex': 7.22.5(@babel/core@7.22.9) + '@babel/plugin-transform-unicode-sets-regex': 7.22.5(@babel/core@7.22.9) '@babel/preset-modules': 0.1.5(@babel/core@7.22.9) - '@babel/types': 7.24.5 - babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.22.9) + '@babel/types': 7.24.0 + babel-plugin-polyfill-corejs2: 0.4.6(@babel/core@7.22.9) babel-plugin-polyfill-corejs3: 0.8.5(@babel/core@7.22.9) babel-plugin-polyfill-regenerator: 0.5.3(@babel/core@7.22.9) - core-js-compat: 3.37.1 + core-js-compat: 3.32.2 semver: 6.3.1 transitivePeerDependencies: - supports-color @@ -35948,7 +36159,7 @@ snapshots: '@babel/compat-data': 7.24.4 '@babel/core': 7.24.4 '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/helper-validator-option': 7.23.5 '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.24.5(@babel/core@7.24.4) '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.24.1(@babel/core@7.24.4) @@ -36054,9 +36265,9 @@ snapshots: '@babel/preset-modules@0.1.5(@babel/core@7.22.9)': dependencies: '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.24.5 '@babel/plugin-proposal-unicode-property-regex': 7.18.6(@babel/core@7.22.9) - '@babel/plugin-transform-dotall-regex': 7.24.1(@babel/core@7.22.9) + '@babel/plugin-transform-dotall-regex': 7.22.5(@babel/core@7.22.9) '@babel/types': 7.24.5 esutils: 2.0.3 @@ -36191,8 +36402,8 @@ snapshots: '@babel/template@7.22.5': dependencies: '@babel/code-frame': 7.24.7 - '@babel/parser': 7.24.4 - '@babel/types': 7.24.5 + '@babel/parser': 7.23.0 + '@babel/types': 7.24.0 '@babel/template@7.24.0': dependencies: @@ -36207,7 +36418,7 @@ snapshots: '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-function-name': 7.23.0 '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-split-export-declaration': 7.24.5 + '@babel/helper-split-export-declaration': 7.22.6 '@babel/parser': 7.24.4 '@babel/types': 7.24.5 debug: 4.3.5(supports-color@8.1.1) @@ -36281,6 +36492,39 @@ snapshots: picocolors: 1.0.0 sisteransi: 1.0.5 + '@clerk/backend@1.2.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@clerk/shared': 2.2.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + cookie: 0.5.0 + snakecase-keys: 5.4.4 + tslib: 2.4.1 + transitivePeerDependencies: + - react + - react-dom + + '@clerk/clerk-sdk-node@5.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@clerk/backend': 1.2.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@clerk/shared': 2.2.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + tslib: 2.4.1 + transitivePeerDependencies: + - react + - react-dom + + '@clerk/shared@2.2.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + glob-to-regexp: 0.4.1 + js-cookie: 3.0.1 + std-env: 3.7.0 + swr: 2.2.5(react@18.3.1) + optionalDependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + + '@clerk/types@4.5.1': + dependencies: + csstype: 3.1.1 + '@codexteam/icons@0.0.4': {} '@codexteam/icons@0.1.0': {} @@ -36590,35 +36834,35 @@ snapshots: dependencies: '@jridgewell/trace-mapping': 0.3.9 - '@csstools/cascade-layer-name-parser@1.0.11(@csstools/css-parser-algorithms@2.6.3(@csstools/css-tokenizer@2.3.1))(@csstools/css-tokenizer@2.3.1)': + '@csstools/cascade-layer-name-parser@1.0.13(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1)': dependencies: - '@csstools/css-parser-algorithms': 2.6.3(@csstools/css-tokenizer@2.3.1) - '@csstools/css-tokenizer': 2.3.1 + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 - '@csstools/color-helpers@4.2.0': {} + '@csstools/color-helpers@4.2.1': {} - '@csstools/css-calc@1.2.2(@csstools/css-parser-algorithms@2.6.3(@csstools/css-tokenizer@2.3.1))(@csstools/css-tokenizer@2.3.1)': + '@csstools/css-calc@1.2.4(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1)': dependencies: - '@csstools/css-parser-algorithms': 2.6.3(@csstools/css-tokenizer@2.3.1) - '@csstools/css-tokenizer': 2.3.1 + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 - '@csstools/css-color-parser@2.0.2(@csstools/css-parser-algorithms@2.6.3(@csstools/css-tokenizer@2.3.1))(@csstools/css-tokenizer@2.3.1)': + '@csstools/css-color-parser@2.0.4(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1)': dependencies: - '@csstools/color-helpers': 4.2.0 - '@csstools/css-calc': 1.2.2(@csstools/css-parser-algorithms@2.6.3(@csstools/css-tokenizer@2.3.1))(@csstools/css-tokenizer@2.3.1) - '@csstools/css-parser-algorithms': 2.6.3(@csstools/css-tokenizer@2.3.1) - '@csstools/css-tokenizer': 2.3.1 + '@csstools/color-helpers': 4.2.1 + '@csstools/css-calc': 1.2.4(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 - '@csstools/css-parser-algorithms@2.6.3(@csstools/css-tokenizer@2.3.1)': + '@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1)': dependencies: - '@csstools/css-tokenizer': 2.3.1 + '@csstools/css-tokenizer': 2.4.1 - '@csstools/css-tokenizer@2.3.1': {} + '@csstools/css-tokenizer@2.4.1': {} - '@csstools/media-query-list-parser@2.1.11(@csstools/css-parser-algorithms@2.6.3(@csstools/css-tokenizer@2.3.1))(@csstools/css-tokenizer@2.3.1)': + '@csstools/media-query-list-parser@2.1.13(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1)': dependencies: - '@csstools/css-parser-algorithms': 2.6.3(@csstools/css-tokenizer@2.3.1) - '@csstools/css-tokenizer': 2.3.1 + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 '@csstools/normalize.css@12.0.0': {} @@ -36630,9 +36874,9 @@ snapshots: '@csstools/postcss-cascade-layers@4.0.4(postcss@8.4.35)': dependencies: - '@csstools/selector-specificity': 3.1.1(postcss-selector-parser@6.0.15) + '@csstools/selector-specificity': 3.1.1(postcss-selector-parser@6.0.16) postcss: 8.4.35 - postcss-selector-parser: 6.0.15 + postcss-selector-parser: 6.0.16 '@csstools/postcss-cascade-layers@4.0.6(postcss@8.4.38)': dependencies: @@ -36646,29 +36890,37 @@ snapshots: postcss: 8.4.31 postcss-value-parser: 4.2.0 - '@csstools/postcss-color-function@3.0.16(postcss@8.4.38)': + '@csstools/postcss-color-function@3.0.19(postcss@8.4.38)': dependencies: - '@csstools/css-color-parser': 2.0.2(@csstools/css-parser-algorithms@2.6.3(@csstools/css-tokenizer@2.3.1))(@csstools/css-tokenizer@2.3.1) - '@csstools/css-parser-algorithms': 2.6.3(@csstools/css-tokenizer@2.3.1) - '@csstools/css-tokenizer': 2.3.1 - '@csstools/postcss-progressive-custom-properties': 3.2.0(postcss@8.4.38) + '@csstools/css-color-parser': 2.0.4(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.38) '@csstools/utilities': 1.0.0(postcss@8.4.38) postcss: 8.4.38 - '@csstools/postcss-color-mix-function@2.0.16(postcss@8.4.38)': + '@csstools/postcss-color-mix-function@2.0.19(postcss@8.4.38)': dependencies: - '@csstools/css-color-parser': 2.0.2(@csstools/css-parser-algorithms@2.6.3(@csstools/css-tokenizer@2.3.1))(@csstools/css-tokenizer@2.3.1) - '@csstools/css-parser-algorithms': 2.6.3(@csstools/css-tokenizer@2.3.1) - '@csstools/css-tokenizer': 2.3.1 - '@csstools/postcss-progressive-custom-properties': 3.2.0(postcss@8.4.38) + '@csstools/css-color-parser': 2.0.4(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.38) '@csstools/utilities': 1.0.0(postcss@8.4.38) postcss: 8.4.38 - '@csstools/postcss-exponential-functions@1.0.7(postcss@8.4.38)': + '@csstools/postcss-content-alt-text@1.0.0(postcss@8.4.38)': dependencies: - '@csstools/css-calc': 1.2.2(@csstools/css-parser-algorithms@2.6.3(@csstools/css-tokenizer@2.3.1))(@csstools/css-tokenizer@2.3.1) - '@csstools/css-parser-algorithms': 2.6.3(@csstools/css-tokenizer@2.3.1) - '@csstools/css-tokenizer': 2.3.1 + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.38) + '@csstools/utilities': 1.0.0(postcss@8.4.38) + postcss: 8.4.38 + + '@csstools/postcss-exponential-functions@1.0.9(postcss@8.4.38)': + dependencies: + '@csstools/css-calc': 1.2.4(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 postcss: 8.4.38 '@csstools/postcss-font-format-keywords@1.0.1(postcss@8.4.31)': @@ -36682,19 +36934,19 @@ snapshots: postcss: 8.4.38 postcss-value-parser: 4.2.0 - '@csstools/postcss-gamut-mapping@1.0.9(postcss@8.4.38)': + '@csstools/postcss-gamut-mapping@1.0.11(postcss@8.4.38)': dependencies: - '@csstools/css-color-parser': 2.0.2(@csstools/css-parser-algorithms@2.6.3(@csstools/css-tokenizer@2.3.1))(@csstools/css-tokenizer@2.3.1) - '@csstools/css-parser-algorithms': 2.6.3(@csstools/css-tokenizer@2.3.1) - '@csstools/css-tokenizer': 2.3.1 + '@csstools/css-color-parser': 2.0.4(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 postcss: 8.4.38 - '@csstools/postcss-gradients-interpolation-method@4.0.17(postcss@8.4.38)': + '@csstools/postcss-gradients-interpolation-method@4.0.20(postcss@8.4.38)': dependencies: - '@csstools/css-color-parser': 2.0.2(@csstools/css-parser-algorithms@2.6.3(@csstools/css-tokenizer@2.3.1))(@csstools/css-tokenizer@2.3.1) - '@csstools/css-parser-algorithms': 2.6.3(@csstools/css-tokenizer@2.3.1) - '@csstools/css-tokenizer': 2.3.1 - '@csstools/postcss-progressive-custom-properties': 3.2.0(postcss@8.4.38) + '@csstools/css-color-parser': 2.0.4(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.38) '@csstools/utilities': 1.0.0(postcss@8.4.38) postcss: 8.4.38 @@ -36703,12 +36955,12 @@ snapshots: postcss: 8.4.31 postcss-value-parser: 4.2.0 - '@csstools/postcss-hwb-function@3.0.15(postcss@8.4.38)': + '@csstools/postcss-hwb-function@3.0.18(postcss@8.4.38)': dependencies: - '@csstools/css-color-parser': 2.0.2(@csstools/css-parser-algorithms@2.6.3(@csstools/css-tokenizer@2.3.1))(@csstools/css-tokenizer@2.3.1) - '@csstools/css-parser-algorithms': 2.6.3(@csstools/css-tokenizer@2.3.1) - '@csstools/css-tokenizer': 2.3.1 - '@csstools/postcss-progressive-custom-properties': 3.2.0(postcss@8.4.38) + '@csstools/css-color-parser': 2.0.4(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.38) '@csstools/utilities': 1.0.0(postcss@8.4.38) postcss: 8.4.38 @@ -36718,9 +36970,9 @@ snapshots: postcss: 8.4.31 postcss-value-parser: 4.2.0 - '@csstools/postcss-ic-unit@3.0.6(postcss@8.4.38)': + '@csstools/postcss-ic-unit@3.0.7(postcss@8.4.38)': dependencies: - '@csstools/postcss-progressive-custom-properties': 3.2.0(postcss@8.4.38) + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.38) '@csstools/utilities': 1.0.0(postcss@8.4.38) postcss: 8.4.38 postcss-value-parser: 4.2.0 @@ -36741,11 +36993,11 @@ snapshots: postcss: 8.4.38 postcss-selector-parser: 6.0.16 - '@csstools/postcss-light-dark-function@1.0.5(postcss@8.4.38)': + '@csstools/postcss-light-dark-function@1.0.8(postcss@8.4.38)': dependencies: - '@csstools/css-parser-algorithms': 2.6.3(@csstools/css-tokenizer@2.3.1) - '@csstools/css-tokenizer': 2.3.1 - '@csstools/postcss-progressive-custom-properties': 3.2.0(postcss@8.4.38) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.38) '@csstools/utilities': 1.0.0(postcss@8.4.38) postcss: 8.4.38 @@ -36766,25 +37018,25 @@ snapshots: postcss: 8.4.38 postcss-value-parser: 4.2.0 - '@csstools/postcss-logical-viewport-units@2.0.9(postcss@8.4.38)': + '@csstools/postcss-logical-viewport-units@2.0.11(postcss@8.4.38)': dependencies: - '@csstools/css-tokenizer': 2.3.1 + '@csstools/css-tokenizer': 2.4.1 '@csstools/utilities': 1.0.0(postcss@8.4.38) postcss: 8.4.38 - '@csstools/postcss-media-minmax@1.1.6(postcss@8.4.38)': + '@csstools/postcss-media-minmax@1.1.8(postcss@8.4.38)': dependencies: - '@csstools/css-calc': 1.2.2(@csstools/css-parser-algorithms@2.6.3(@csstools/css-tokenizer@2.3.1))(@csstools/css-tokenizer@2.3.1) - '@csstools/css-parser-algorithms': 2.6.3(@csstools/css-tokenizer@2.3.1) - '@csstools/css-tokenizer': 2.3.1 - '@csstools/media-query-list-parser': 2.1.11(@csstools/css-parser-algorithms@2.6.3(@csstools/css-tokenizer@2.3.1))(@csstools/css-tokenizer@2.3.1) + '@csstools/css-calc': 1.2.4(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/media-query-list-parser': 2.1.13(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) postcss: 8.4.38 - '@csstools/postcss-media-queries-aspect-ratio-number-values@2.0.9(postcss@8.4.38)': + '@csstools/postcss-media-queries-aspect-ratio-number-values@2.0.11(postcss@8.4.38)': dependencies: - '@csstools/css-parser-algorithms': 2.6.3(@csstools/css-tokenizer@2.3.1) - '@csstools/css-tokenizer': 2.3.1 - '@csstools/media-query-list-parser': 2.1.11(@csstools/css-parser-algorithms@2.6.3(@csstools/css-tokenizer@2.3.1))(@csstools/css-tokenizer@2.3.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/media-query-list-parser': 2.1.13(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) postcss: 8.4.38 '@csstools/postcss-nested-calc@1.0.0(postcss@8.4.31)': @@ -36814,12 +37066,12 @@ snapshots: postcss: 8.4.31 postcss-value-parser: 4.2.0 - '@csstools/postcss-oklab-function@3.0.16(postcss@8.4.38)': + '@csstools/postcss-oklab-function@3.0.19(postcss@8.4.38)': dependencies: - '@csstools/css-color-parser': 2.0.2(@csstools/css-parser-algorithms@2.6.3(@csstools/css-tokenizer@2.3.1))(@csstools/css-tokenizer@2.3.1) - '@csstools/css-parser-algorithms': 2.6.3(@csstools/css-tokenizer@2.3.1) - '@csstools/css-tokenizer': 2.3.1 - '@csstools/postcss-progressive-custom-properties': 3.2.0(postcss@8.4.38) + '@csstools/css-color-parser': 2.0.4(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.38) '@csstools/utilities': 1.0.0(postcss@8.4.38) postcss: 8.4.38 @@ -36828,17 +37080,17 @@ snapshots: postcss: 8.4.31 postcss-value-parser: 4.2.0 - '@csstools/postcss-progressive-custom-properties@3.2.0(postcss@8.4.38)': + '@csstools/postcss-progressive-custom-properties@3.3.0(postcss@8.4.38)': dependencies: postcss: 8.4.38 postcss-value-parser: 4.2.0 - '@csstools/postcss-relative-color-syntax@2.0.16(postcss@8.4.38)': + '@csstools/postcss-relative-color-syntax@2.0.19(postcss@8.4.38)': dependencies: - '@csstools/css-color-parser': 2.0.2(@csstools/css-parser-algorithms@2.6.3(@csstools/css-tokenizer@2.3.1))(@csstools/css-tokenizer@2.3.1) - '@csstools/css-parser-algorithms': 2.6.3(@csstools/css-tokenizer@2.3.1) - '@csstools/css-tokenizer': 2.3.1 - '@csstools/postcss-progressive-custom-properties': 3.2.0(postcss@8.4.38) + '@csstools/css-color-parser': 2.0.4(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.38) '@csstools/utilities': 1.0.0(postcss@8.4.38) postcss: 8.4.38 @@ -36852,11 +37104,11 @@ snapshots: postcss: 8.4.31 postcss-value-parser: 4.2.0 - '@csstools/postcss-stepped-value-functions@3.0.8(postcss@8.4.38)': + '@csstools/postcss-stepped-value-functions@3.0.10(postcss@8.4.38)': dependencies: - '@csstools/css-calc': 1.2.2(@csstools/css-parser-algorithms@2.6.3(@csstools/css-tokenizer@2.3.1))(@csstools/css-tokenizer@2.3.1) - '@csstools/css-parser-algorithms': 2.6.3(@csstools/css-tokenizer@2.3.1) - '@csstools/css-tokenizer': 2.3.1 + '@csstools/css-calc': 1.2.4(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 postcss: 8.4.38 '@csstools/postcss-text-decoration-shorthand@1.0.0(postcss@8.4.31)': @@ -36864,9 +37116,9 @@ snapshots: postcss: 8.4.31 postcss-value-parser: 4.2.0 - '@csstools/postcss-text-decoration-shorthand@3.0.6(postcss@8.4.38)': + '@csstools/postcss-text-decoration-shorthand@3.0.7(postcss@8.4.38)': dependencies: - '@csstools/color-helpers': 4.2.0 + '@csstools/color-helpers': 4.2.1 postcss: 8.4.38 postcss-value-parser: 4.2.0 @@ -36875,11 +37127,11 @@ snapshots: postcss: 8.4.31 postcss-value-parser: 4.2.0 - '@csstools/postcss-trigonometric-functions@3.0.8(postcss@8.4.38)': + '@csstools/postcss-trigonometric-functions@3.0.10(postcss@8.4.38)': dependencies: - '@csstools/css-calc': 1.2.2(@csstools/css-parser-algorithms@2.6.3(@csstools/css-tokenizer@2.3.1))(@csstools/css-tokenizer@2.3.1) - '@csstools/css-parser-algorithms': 2.6.3(@csstools/css-tokenizer@2.3.1) - '@csstools/css-tokenizer': 2.3.1 + '@csstools/css-calc': 1.2.4(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 postcss: 8.4.38 '@csstools/postcss-unset-value@1.0.2(postcss@8.4.31)': @@ -36898,10 +37150,6 @@ snapshots: dependencies: postcss-selector-parser: 6.0.15 - '@csstools/selector-specificity@3.1.1(postcss-selector-parser@6.0.15)': - dependencies: - postcss-selector-parser: 6.0.15 - '@csstools/selector-specificity@3.1.1(postcss-selector-parser@6.0.16)': dependencies: postcss-selector-parser: 6.0.16 @@ -37108,7 +37356,7 @@ snapshots: '@emotion/memoize': 0.8.0 '@emotion/unitless': 0.8.0 '@emotion/utils': 1.2.0 - csstype: 3.1.2 + csstype: 3.1.3 '@emotion/serialize@1.1.4': dependencies: @@ -37209,6 +37457,9 @@ snapshots: '@esbuild/aix-ppc64@0.20.1': optional: true + '@esbuild/aix-ppc64@0.21.4': + optional: true + '@esbuild/android-arm64@0.18.17': optional: true @@ -37221,6 +37472,9 @@ snapshots: '@esbuild/android-arm64@0.20.1': optional: true + '@esbuild/android-arm64@0.21.4': + optional: true + '@esbuild/android-arm@0.18.17': optional: true @@ -37233,6 +37487,9 @@ snapshots: '@esbuild/android-arm@0.20.1': optional: true + '@esbuild/android-arm@0.21.4': + optional: true + '@esbuild/android-x64@0.18.17': optional: true @@ -37245,6 +37502,9 @@ snapshots: '@esbuild/android-x64@0.20.1': optional: true + '@esbuild/android-x64@0.21.4': + optional: true + '@esbuild/darwin-arm64@0.18.17': optional: true @@ -37257,6 +37517,9 @@ snapshots: '@esbuild/darwin-arm64@0.20.1': optional: true + '@esbuild/darwin-arm64@0.21.4': + optional: true + '@esbuild/darwin-x64@0.18.17': optional: true @@ -37269,6 +37532,9 @@ snapshots: '@esbuild/darwin-x64@0.20.1': optional: true + '@esbuild/darwin-x64@0.21.4': + optional: true + '@esbuild/freebsd-arm64@0.18.17': optional: true @@ -37281,6 +37547,9 @@ snapshots: '@esbuild/freebsd-arm64@0.20.1': optional: true + '@esbuild/freebsd-arm64@0.21.4': + optional: true + '@esbuild/freebsd-x64@0.18.17': optional: true @@ -37293,6 +37562,9 @@ snapshots: '@esbuild/freebsd-x64@0.20.1': optional: true + '@esbuild/freebsd-x64@0.21.4': + optional: true + '@esbuild/linux-arm64@0.18.17': optional: true @@ -37305,6 +37577,9 @@ snapshots: '@esbuild/linux-arm64@0.20.1': optional: true + '@esbuild/linux-arm64@0.21.4': + optional: true + '@esbuild/linux-arm@0.18.17': optional: true @@ -37317,6 +37592,9 @@ snapshots: '@esbuild/linux-arm@0.20.1': optional: true + '@esbuild/linux-arm@0.21.4': + optional: true + '@esbuild/linux-ia32@0.18.17': optional: true @@ -37329,6 +37607,9 @@ snapshots: '@esbuild/linux-ia32@0.20.1': optional: true + '@esbuild/linux-ia32@0.21.4': + optional: true + '@esbuild/linux-loong64@0.18.17': optional: true @@ -37341,6 +37622,9 @@ snapshots: '@esbuild/linux-loong64@0.20.1': optional: true + '@esbuild/linux-loong64@0.21.4': + optional: true + '@esbuild/linux-mips64el@0.18.17': optional: true @@ -37353,6 +37637,9 @@ snapshots: '@esbuild/linux-mips64el@0.20.1': optional: true + '@esbuild/linux-mips64el@0.21.4': + optional: true + '@esbuild/linux-ppc64@0.18.17': optional: true @@ -37365,6 +37652,9 @@ snapshots: '@esbuild/linux-ppc64@0.20.1': optional: true + '@esbuild/linux-ppc64@0.21.4': + optional: true + '@esbuild/linux-riscv64@0.18.17': optional: true @@ -37377,6 +37667,9 @@ snapshots: '@esbuild/linux-riscv64@0.20.1': optional: true + '@esbuild/linux-riscv64@0.21.4': + optional: true + '@esbuild/linux-s390x@0.18.17': optional: true @@ -37389,6 +37682,9 @@ snapshots: '@esbuild/linux-s390x@0.20.1': optional: true + '@esbuild/linux-s390x@0.21.4': + optional: true + '@esbuild/linux-x64@0.18.17': optional: true @@ -37401,6 +37697,9 @@ snapshots: '@esbuild/linux-x64@0.20.1': optional: true + '@esbuild/linux-x64@0.21.4': + optional: true + '@esbuild/netbsd-x64@0.18.17': optional: true @@ -37413,6 +37712,9 @@ snapshots: '@esbuild/netbsd-x64@0.20.1': optional: true + '@esbuild/netbsd-x64@0.21.4': + optional: true + '@esbuild/openbsd-x64@0.18.17': optional: true @@ -37425,6 +37727,9 @@ snapshots: '@esbuild/openbsd-x64@0.20.1': optional: true + '@esbuild/openbsd-x64@0.21.4': + optional: true + '@esbuild/sunos-x64@0.18.17': optional: true @@ -37437,6 +37742,9 @@ snapshots: '@esbuild/sunos-x64@0.20.1': optional: true + '@esbuild/sunos-x64@0.21.4': + optional: true + '@esbuild/win32-arm64@0.18.17': optional: true @@ -37449,6 +37757,9 @@ snapshots: '@esbuild/win32-arm64@0.20.1': optional: true + '@esbuild/win32-arm64@0.21.4': + optional: true + '@esbuild/win32-ia32@0.18.17': optional: true @@ -37461,6 +37772,9 @@ snapshots: '@esbuild/win32-ia32@0.20.1': optional: true + '@esbuild/win32-ia32@0.21.4': + optional: true + '@esbuild/win32-x64@0.18.17': optional: true @@ -37473,6 +37787,9 @@ snapshots: '@esbuild/win32-x64@0.20.1': optional: true + '@esbuild/win32-x64@0.21.4': + optional: true + '@eslint-community/eslint-utils@4.4.0(eslint@8.38.0)': dependencies: eslint: 8.38.0 @@ -37585,7 +37902,7 @@ snapshots: '@floating-ui/core@0.3.1': {} - '@floating-ui/core@1.6.4': + '@floating-ui/core@1.6.2': dependencies: '@floating-ui/utils': 0.2.4 @@ -37595,7 +37912,7 @@ snapshots: '@floating-ui/dom@1.6.7': dependencies: - '@floating-ui/core': 1.6.4 + '@floating-ui/core': 1.6.2 '@floating-ui/utils': 0.2.4 '@floating-ui/react-dom@1.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': @@ -37837,7 +38154,7 @@ snapshots: '@hokify/agenda@6.3.0': dependencies: - cron-parser: 4.8.1 + cron-parser: 4.9.0 date.js: 0.3.3 debug: 4.3.4(supports-color@8.1.1) human-interval: 2.0.1 @@ -38726,7 +39043,7 @@ snapshots: dependencies: '@lerna/command': 5.6.2 '@lerna/output': 5.6.2 - envinfo: 7.13.0 + envinfo: 7.8.1 '@lerna/init@5.6.2': dependencies: @@ -39044,7 +39361,7 @@ snapshots: transitivePeerDependencies: - debug - '@mantine/code-highlight@7.10.2(@mantine/core@7.10.1(@mantine/hooks@7.10.1(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.10.1(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@mantine/code-highlight@7.11.1(@mantine/core@7.10.1(@mantine/hooks@7.10.1(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.10.1(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@mantine/core': 7.10.1(@mantine/hooks@7.10.1(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@mantine/hooks': 7.10.1(react@18.3.1) @@ -39183,7 +39500,7 @@ snapshots: nopt: 5.0.0 npmlog: 5.0.1 rimraf: 3.0.2 - semver: 7.6.2 + semver: 7.5.4 tar: 7.1.0 transitivePeerDependencies: - encoding @@ -43089,7 +43406,7 @@ snapshots: '@rrweb/types@2.0.0-alpha.13': dependencies: - rrweb-snapshot: 2.0.0-alpha.15 + rrweb-snapshot: 2.0.0-alpha.13 '@rushstack/eslint-patch@1.2.0': {} @@ -44489,6 +44806,8 @@ snapshots: dependencies: solid-js: 1.8.17 + '@stablelib/base64@1.0.1': {} + '@stdlib/array-float32@0.0.6': dependencies: '@stdlib/assert-has-float32array-support': 0.0.8 @@ -45843,12 +46162,12 @@ snapshots: '@swc/core': 1.3.107(@swc/helpers@0.5.2) '@types/node': 16.11.7 '@types/semver': 7.3.13 - babel-loader: 9.1.3(@babel/core@7.23.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.20)) + babel-loader: 9.1.2(@babel/core@7.23.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.20)) babel-plugin-named-exports-order: 0.0.2 browser-assert: 1.2.1 case-sensitive-paths-webpack-plugin: 2.4.0 constants-browserify: 1.0.0 - css-loader: 6.8.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.20)) + css-loader: 6.7.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.20)) express: 4.19.2 fork-ts-checker-webpack-plugin: 8.0.0(typescript@4.9.5)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.20)) fs-extra: 11.2.0 @@ -45903,12 +46222,12 @@ snapshots: '@swc/core': 1.3.107(@swc/helpers@0.5.2) '@types/node': 16.11.7 '@types/semver': 7.3.13 - babel-loader: 9.1.3(@babel/core@7.23.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))) + babel-loader: 9.1.2(@babel/core@7.23.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))) babel-plugin-named-exports-order: 0.0.2 browser-assert: 1.2.1 case-sensitive-paths-webpack-plugin: 2.4.0 constants-browserify: 1.0.0 - css-loader: 6.8.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))) + css-loader: 6.7.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))) express: 4.19.2 fork-ts-checker-webpack-plugin: 8.0.0(typescript@4.9.5)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))) fs-extra: 11.2.0 @@ -45963,12 +46282,12 @@ snapshots: '@swc/core': 1.3.107(@swc/helpers@0.5.2) '@types/node': 16.11.7 '@types/semver': 7.3.13 - babel-loader: 9.1.3(@babel/core@7.23.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.82.1))) + babel-loader: 9.1.2(@babel/core@7.23.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.82.1))) babel-plugin-named-exports-order: 0.0.2 browser-assert: 1.2.1 case-sensitive-paths-webpack-plugin: 2.4.0 constants-browserify: 1.0.0 - css-loader: 6.8.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.82.1))) + css-loader: 6.7.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.82.1))) express: 4.19.2 fork-ts-checker-webpack-plugin: 8.0.0(typescript@4.9.5)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.82.1))) fs-extra: 11.2.0 @@ -46161,7 +46480,7 @@ snapshots: '@storybook/codemod@7.4.2': dependencies: '@babel/core': 7.24.4 - '@babel/preset-env': 7.24.5(@babel/core@7.24.4) + '@babel/preset-env': 7.23.2(@babel/core@7.24.4) '@babel/types': 7.24.5 '@storybook/csf': 0.1.7 '@storybook/csf-tools': 7.4.2 @@ -46170,7 +46489,7 @@ snapshots: '@types/cross-spawn': 6.0.3 cross-spawn: 7.0.3 globby: 11.1.0 - jscodeshift: 0.14.0(@babel/preset-env@7.24.5(@babel/core@7.24.4)) + jscodeshift: 0.14.0(@babel/preset-env@7.23.2(@babel/core@7.24.4)) lodash: 4.17.21 prettier: 2.8.8 recast: 0.23.4 @@ -47700,9 +48019,11 @@ snapshots: '@types/bcryptjs@2.4.6': {} + '@types/bluebird@3.5.38': {} + '@types/body-parser@1.19.2': dependencies: - '@types/connect': 3.4.35 + '@types/connect': 3.4.36 '@types/node': 20.14.10 '@types/bonjour@3.5.10': @@ -47746,10 +48067,6 @@ snapshots: '@types/express-serve-static-core': 4.17.33 '@types/node': 20.14.10 - '@types/connect@3.4.35': - dependencies: - '@types/node': 20.14.10 - '@types/connect@3.4.36': dependencies: '@types/node': 20.14.10 @@ -47960,6 +48277,13 @@ snapshots: '@types/qs': 6.9.7 '@types/serve-static': 1.15.1 + '@types/express@4.17.21': + dependencies: + '@types/body-parser': 1.19.2 + '@types/express-serve-static-core': 4.17.33 + '@types/qs': 6.9.7 + '@types/serve-static': 1.15.1 + '@types/find-cache-dir@3.2.1': {} '@types/geojson@7946.0.10': {} @@ -48267,7 +48591,7 @@ snapshots: '@types/passport-jwt@3.0.8': dependencies: - '@types/express': 4.17.17 + '@types/express': 4.17.21 '@types/jsonwebtoken': 8.5.9 '@types/passport-strategy': 0.2.35 @@ -48464,7 +48788,7 @@ snapshots: '@types/testing-library__jest-dom@5.14.5': dependencies: - '@types/jest': 29.5.12 + '@types/jest': 29.5.2 '@types/through@0.0.30': dependencies: @@ -49454,7 +49778,7 @@ snapshots: dependencies: '@babel/helper-module-imports': 7.22.15 '@babel/plugin-syntax-jsx': 7.22.5(@babel/core@7.21.4) - '@babel/template': 7.24.0 + '@babel/template': 7.22.15 '@babel/traverse': 7.23.2 '@babel/types': 7.23.0 '@vue/babel-helper-vue-transform-on': 1.0.2 @@ -49477,7 +49801,7 @@ snapshots: '@babel/parser': 7.24.4 '@vue/shared': 3.3.7 estree-walker: 2.0.2 - source-map-js: 1.2.0 + source-map-js: 1.0.2 '@vue/compiler-core@3.4.19': dependencies: @@ -49485,7 +49809,7 @@ snapshots: '@vue/shared': 3.4.19 entities: 4.5.0 estree-walker: 2.0.2 - source-map-js: 1.2.0 + source-map-js: 1.0.2 '@vue/compiler-dom@3.2.47': dependencies: @@ -49525,7 +49849,7 @@ snapshots: estree-walker: 2.0.2 magic-string: 0.30.10 postcss: 8.4.38 - source-map-js: 1.2.0 + source-map-js: 1.0.2 '@vue/compiler-ssr@3.2.47': dependencies: @@ -49760,9 +50084,9 @@ snapshots: '@webassemblyjs/ast': 1.11.5 '@xtuc/long': 4.2.2 - '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.20.1)(webpack-cli@5.1.4))': + '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.21.4)(webpack-cli@5.1.4))': dependencies: - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.20.1)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.21.4)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0) '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.82.1))(webpack@5.82.1(@swc/core@1.3.107(@swc/helpers@0.5.2))(webpack-cli@5.1.4))': @@ -49770,9 +50094,9 @@ snapshots: webpack: 5.82.1(@swc/core@1.3.107(@swc/helpers@0.5.2))(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.82.1) - '@webpack-cli/info@2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.20.1)(webpack-cli@5.1.4))': + '@webpack-cli/info@2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.21.4)(webpack-cli@5.1.4))': dependencies: - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.20.1)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.21.4)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0) '@webpack-cli/info@2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.82.1))(webpack@5.82.1(@swc/core@1.3.107(@swc/helpers@0.5.2))(webpack-cli@5.1.4))': @@ -49780,9 +50104,9 @@ snapshots: webpack: 5.82.1(@swc/core@1.3.107(@swc/helpers@0.5.2))(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.82.1) - '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.20.1)(webpack-cli@5.1.4))': + '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.21.4)(webpack-cli@5.1.4))': dependencies: - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.20.1)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.21.4)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0) '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.82.1))(webpack@5.82.1(@swc/core@1.3.107(@swc/helpers@0.5.2))(webpack-cli@5.1.4))': @@ -50675,8 +50999,8 @@ snapshots: autoprefixer@10.4.19(postcss@8.4.38): dependencies: - browserslist: 4.23.0 - caniuse-lite: 1.0.30001636 + browserslist: 4.23.2 + caniuse-lite: 1.0.30001641 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.0.0 @@ -50729,7 +51053,7 @@ snapshots: axios@0.26.1: dependencies: - follow-redirects: 1.15.6(debug@4.3.4) + follow-redirects: 1.15.5 transitivePeerDependencies: - debug @@ -50856,34 +51180,34 @@ snapshots: schema-utils: 2.7.1 webpack: 5.82.1(@swc/core@1.3.107(@swc/helpers@0.5.2))(webpack-cli@5.1.4) - babel-loader@9.1.3(@babel/core@7.22.9)(webpack@5.88.2(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.17)): - dependencies: - '@babel/core': 7.22.9 - find-cache-dir: 4.0.0 - schema-utils: 4.0.0 - webpack: 5.88.2(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.17) - - babel-loader@9.1.3(@babel/core@7.23.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.20)): + babel-loader@9.1.2(@babel/core@7.23.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.20)): dependencies: '@babel/core': 7.23.2 - find-cache-dir: 4.0.0 + find-cache-dir: 3.3.2 schema-utils: 4.0.0 webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.20) - babel-loader@9.1.3(@babel/core@7.23.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.82.1))): + babel-loader@9.1.2(@babel/core@7.23.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.82.1))): dependencies: '@babel/core': 7.23.2 - find-cache-dir: 4.0.0 + find-cache-dir: 3.3.2 schema-utils: 4.0.0 webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.82.1)) - babel-loader@9.1.3(@babel/core@7.23.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))): + babel-loader@9.1.2(@babel/core@7.23.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))): dependencies: '@babel/core': 7.23.2 - find-cache-dir: 4.0.0 + find-cache-dir: 3.3.2 schema-utils: 4.0.0 webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2)) + babel-loader@9.1.3(@babel/core@7.22.9)(webpack@5.88.2(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.17)): + dependencies: + '@babel/core': 7.22.9 + find-cache-dir: 4.0.0 + schema-utils: 4.0.0 + webpack: 5.88.2(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.17) + babel-plugin-add-react-displayname@0.0.5: {} babel-plugin-const-enum@1.2.0(@babel/core@7.24.4): @@ -50901,7 +51225,7 @@ snapshots: babel-plugin-istanbul@6.1.1: dependencies: - '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-plugin-utils': 7.22.5 '@istanbuljs/load-nyc-config': 1.1.0 '@istanbuljs/schema': 0.1.3 istanbul-lib-instrument: 5.2.1 @@ -50950,15 +51274,6 @@ snapshots: babel-plugin-named-exports-order@0.0.2: {} - babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.22.9): - dependencies: - '@babel/compat-data': 7.24.4 - '@babel/core': 7.22.9 - '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.22.9) - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.24.4): dependencies: '@babel/compat-data': 7.24.4 @@ -50977,6 +51292,15 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-polyfill-corejs2@0.4.6(@babel/core@7.22.9): + dependencies: + '@babel/compat-data': 7.23.2 + '@babel/core': 7.22.9 + '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.22.9) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + babel-plugin-polyfill-corejs2@0.4.6(@babel/core@7.24.4): dependencies: '@babel/compat-data': 7.23.2 @@ -51427,7 +51751,7 @@ snapshots: browserslist@4.21.10: dependencies: - caniuse-lite: 1.0.30001636 + caniuse-lite: 1.0.30001589 electron-to-chromium: 1.4.508 node-releases: 2.0.13 update-browserslist-db: 1.0.11(browserslist@4.21.10) @@ -51446,6 +51770,13 @@ snapshots: node-releases: 2.0.14 update-browserslist-db: 1.0.13(browserslist@4.23.0) + browserslist@4.23.2: + dependencies: + caniuse-lite: 1.0.30001641 + electron-to-chromium: 1.4.823 + node-releases: 2.0.14 + update-browserslist-db: 1.1.0(browserslist@4.23.2) + bs-logger@0.2.6: dependencies: fast-json-stable-stringify: 2.1.0 @@ -51514,7 +51845,7 @@ snapshots: bullmq@3.10.4: dependencies: - cron-parser: 4.8.1 + cron-parser: 4.9.0 glob: 8.1.0 ioredis: 5.3.2 lodash: 4.17.21 @@ -51732,7 +52063,7 @@ snapshots: caniuse-api@3.0.0: dependencies: browserslist: 4.23.0 - caniuse-lite: 1.0.30001636 + caniuse-lite: 1.0.30001589 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 @@ -51740,7 +52071,7 @@ snapshots: caniuse-lite@1.0.30001589: {} - caniuse-lite@1.0.30001636: {} + caniuse-lite@1.0.30001641: {} case-sensitive-paths-webpack-plugin@2.4.0: {} @@ -51963,7 +52294,7 @@ snapshots: dependencies: '@types/validator': 13.7.14 libphonenumber-js: 1.10.26 - validator: 13.9.0 + validator: 13.12.0 classcat@5.0.4: {} @@ -52265,11 +52596,11 @@ snapshots: dependencies: mime-db: 1.52.0 - compression-webpack-plugin@10.0.0(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.20.1)(webpack-cli@5.1.4)): + compression-webpack-plugin@10.0.0(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.21.4)(webpack-cli@5.1.4)): dependencies: schema-utils: 4.0.0 serialize-javascript: 6.0.1 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.20.1)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.21.4)(webpack-cli@5.1.4) compression-webpack-plugin@10.0.0(webpack@5.82.1(@swc/core@1.3.107(@swc/helpers@0.5.2))(webpack-cli@5.1.4)): dependencies: @@ -52486,7 +52817,7 @@ snapshots: globby: 13.1.3 normalize-path: 3.0.0 schema-utils: 4.0.0 - serialize-javascript: 6.0.2 + serialize-javascript: 6.0.1 webpack: 5.88.2(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.17) core-js-compat@3.32.2: @@ -52949,36 +53280,36 @@ snapshots: postcss-selector-parser: 6.0.16 postcss-value-parser: 4.2.0 - css-loader@6.8.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.20)): + css-loader@6.7.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.20)): dependencies: icss-utils: 5.1.0(postcss@8.4.38) postcss: 8.4.38 postcss-modules-extract-imports: 3.0.0(postcss@8.4.38) - postcss-modules-local-by-default: 4.0.3(postcss@8.4.38) + postcss-modules-local-by-default: 4.0.0(postcss@8.4.38) postcss-modules-scope: 3.0.0(postcss@8.4.38) postcss-modules-values: 4.0.0(postcss@8.4.38) postcss-value-parser: 4.2.0 semver: 7.6.2 webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.20) - css-loader@6.8.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.82.1))): + css-loader@6.7.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.82.1))): dependencies: icss-utils: 5.1.0(postcss@8.4.38) postcss: 8.4.38 postcss-modules-extract-imports: 3.0.0(postcss@8.4.38) - postcss-modules-local-by-default: 4.0.3(postcss@8.4.38) + postcss-modules-local-by-default: 4.0.0(postcss@8.4.38) postcss-modules-scope: 3.0.0(postcss@8.4.38) postcss-modules-values: 4.0.0(postcss@8.4.38) postcss-value-parser: 4.2.0 semver: 7.6.2 webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.82.1)) - css-loader@6.8.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))): + css-loader@6.7.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))): dependencies: icss-utils: 5.1.0(postcss@8.4.38) postcss: 8.4.38 postcss-modules-extract-imports: 3.0.0(postcss@8.4.38) - postcss-modules-local-by-default: 4.0.3(postcss@8.4.38) + postcss-modules-local-by-default: 4.0.0(postcss@8.4.38) postcss-modules-scope: 3.0.0(postcss@8.4.38) postcss-modules-values: 4.0.0(postcss@8.4.38) postcss-value-parser: 4.2.0 @@ -53003,7 +53334,7 @@ snapshots: jest-worker: 27.5.1 postcss: 8.4.38 schema-utils: 4.0.0 - serialize-javascript: 6.0.2 + serialize-javascript: 6.0.1 source-map: 0.6.1 webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.20) optionalDependencies: @@ -53015,7 +53346,7 @@ snapshots: jest-worker: 27.5.1 postcss: 8.4.38 schema-utils: 4.0.0 - serialize-javascript: 6.0.2 + serialize-javascript: 6.0.1 source-map: 0.6.1 webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2)) @@ -53086,7 +53417,7 @@ snapshots: cssdb@7.5.4: {} - cssdb@8.0.2: {} + cssdb@8.1.0: {} cssesc@3.0.0: {} @@ -53164,6 +53495,8 @@ snapshots: csstype@3.0.9: {} + csstype@3.1.1: {} + csstype@3.1.2: {} csstype@3.1.3: {} @@ -53801,6 +54134,8 @@ snapshots: electron-to-chromium@1.4.682: {} + electron-to-chromium@1.4.823: {} + elegant-spinner@1.0.1: {} email-addresses@5.0.0: {} @@ -54033,6 +54368,8 @@ snapshots: es6-error@4.1.1: {} + es6-promise@4.2.8: {} + esbuild-android-64@0.14.47: optional: true @@ -54083,19 +54420,19 @@ snapshots: esbuild-plugin-alias@0.2.1: {} - esbuild-plugin-compress@1.0.1(esbuild@0.20.1): + esbuild-plugin-compress@1.0.1(esbuild@0.21.4): dependencies: chalk: 4.1.2 - esbuild: 0.20.1 + esbuild: 0.21.4 fs-extra: 10.1.0 micromatch: 4.0.5 - esbuild-plugin-solid@0.5.0(esbuild@0.20.1)(solid-js@1.8.17): + esbuild-plugin-solid@0.5.0(esbuild@0.21.4)(solid-js@1.8.17): dependencies: '@babel/core': 7.24.4 '@babel/preset-typescript': 7.23.2(@babel/core@7.24.4) babel-preset-solid: 1.8.17(@babel/core@7.24.4) - esbuild: 0.20.1 + esbuild: 0.21.4 solid-js: 1.8.17 transitivePeerDependencies: - supports-color @@ -54256,6 +54593,32 @@ snapshots: '@esbuild/win32-ia32': 0.20.1 '@esbuild/win32-x64': 0.20.1 + esbuild@0.21.4: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.4 + '@esbuild/android-arm': 0.21.4 + '@esbuild/android-arm64': 0.21.4 + '@esbuild/android-x64': 0.21.4 + '@esbuild/darwin-arm64': 0.21.4 + '@esbuild/darwin-x64': 0.21.4 + '@esbuild/freebsd-arm64': 0.21.4 + '@esbuild/freebsd-x64': 0.21.4 + '@esbuild/linux-arm': 0.21.4 + '@esbuild/linux-arm64': 0.21.4 + '@esbuild/linux-ia32': 0.21.4 + '@esbuild/linux-loong64': 0.21.4 + '@esbuild/linux-mips64el': 0.21.4 + '@esbuild/linux-ppc64': 0.21.4 + '@esbuild/linux-riscv64': 0.21.4 + '@esbuild/linux-s390x': 0.21.4 + '@esbuild/linux-x64': 0.21.4 + '@esbuild/netbsd-x64': 0.21.4 + '@esbuild/openbsd-x64': 0.21.4 + '@esbuild/sunos-x64': 0.21.4 + '@esbuild/win32-arm64': 0.21.4 + '@esbuild/win32-ia32': 0.21.4 + '@esbuild/win32-x64': 0.21.4 + escalade@3.1.2: {} escape-html@1.0.3: {} @@ -54398,7 +54761,7 @@ snapshots: eslint-import-resolver-node@0.3.7: dependencies: - debug: 3.2.7(supports-color@8.1.1) + debug: 3.2.7(supports-color@5.5.0) is-core-module: 2.13.0 resolve: 1.22.8 transitivePeerDependencies: @@ -54407,7 +54770,7 @@ snapshots: eslint-import-resolver-webpack@0.13.7(eslint-plugin-import@2.28.1)(webpack@5.88.2(@swc/core@1.3.107(@swc/helpers@0.5.2))): dependencies: array.prototype.find: 2.2.2 - debug: 3.2.7(supports-color@8.1.1) + debug: 3.2.7(supports-color@5.5.0) enhanced-resolve: 0.9.1 eslint-plugin-import: 2.28.1(@typescript-eslint/parser@5.58.0(eslint@8.38.0)(typescript@4.9.5))(eslint-import-resolver-webpack@0.13.7)(eslint@8.38.0) find-root: 1.1.0 @@ -54424,7 +54787,7 @@ snapshots: eslint-module-utils@2.8.0(@typescript-eslint/parser@5.58.0(eslint@8.38.0)(typescript@4.9.5))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-webpack@0.13.7(eslint-plugin-import@2.28.1)(webpack@5.88.2(@swc/core@1.3.107(@swc/helpers@0.5.2))))(eslint@8.38.0): dependencies: - debug: 3.2.7(supports-color@8.1.1) + debug: 3.2.7(supports-color@5.5.0) optionalDependencies: '@typescript-eslint/parser': 5.58.0(eslint@8.38.0)(typescript@4.9.5) eslint: 8.38.0 @@ -54435,7 +54798,7 @@ snapshots: eslint-module-utils@2.8.0(@typescript-eslint/parser@5.58.0(eslint@8.57.0)(typescript@4.9.5))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-webpack@0.13.7(eslint-plugin-import@2.28.1)(webpack@5.88.2(@swc/core@1.3.107(@swc/helpers@0.5.2))))(eslint@8.57.0): dependencies: - debug: 3.2.7(supports-color@8.1.1) + debug: 3.2.7(supports-color@5.5.0) optionalDependencies: '@typescript-eslint/parser': 5.58.0(eslint@8.57.0)(typescript@4.9.5) eslint: 8.57.0 @@ -54513,7 +54876,7 @@ snapshots: array.prototype.findlastindex: 1.2.3 array.prototype.flat: 1.3.1 array.prototype.flatmap: 1.3.1 - debug: 3.2.7(supports-color@8.1.1) + debug: 3.2.7(supports-color@5.5.0) doctrine: 2.1.0 eslint: 8.38.0 eslint-import-resolver-node: 0.3.7 @@ -54540,7 +54903,7 @@ snapshots: array.prototype.findlastindex: 1.2.3 array.prototype.flat: 1.3.1 array.prototype.flatmap: 1.3.1 - debug: 3.2.7(supports-color@8.1.1) + debug: 3.2.7(supports-color@5.5.0) doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.7 @@ -54943,7 +55306,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -54955,7 +55318,7 @@ snapshots: file-entry-cache: 6.0.1 find-up: 5.0.0 glob-parent: 6.0.2 - globals: 13.23.0 + globals: 13.24.0 graphemer: 1.4.0 ignore: 5.2.4 imurmurhash: 0.1.4 @@ -55469,6 +55832,8 @@ snapshots: fast-safe-stringify@2.1.1: {} + fast-sha256@1.3.0: {} + fast-text-encoding@1.0.6: {} fast-url-parser@1.1.3: @@ -55760,7 +56125,7 @@ snapshots: flat-cache@3.1.0: dependencies: - flatted: 3.2.7 + flatted: 3.3.1 keyv: 4.5.4 rimraf: 3.0.2 @@ -55870,7 +56235,7 @@ snapshots: minimatch: 3.1.2 node-abort-controller: 3.1.1 schema-utils: 3.3.0 - semver: 7.6.2 + semver: 7.5.4 tapable: 2.2.1 typescript: 4.9.5 webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.20) @@ -55887,7 +56252,7 @@ snapshots: minimatch: 3.1.2 node-abort-controller: 3.1.1 schema-utils: 3.3.0 - semver: 7.6.2 + semver: 7.5.4 tapable: 2.2.1 typescript: 4.9.5 webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.82.1)) @@ -55904,7 +56269,7 @@ snapshots: minimatch: 3.1.2 node-abort-controller: 3.1.1 schema-utils: 3.3.0 - semver: 7.6.2 + semver: 7.5.4 tapable: 2.2.1 typescript: 4.9.5 webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2)) @@ -55921,7 +56286,7 @@ snapshots: minimatch: 3.1.2 node-abort-controller: 3.1.1 schema-utils: 3.3.0 - semver: 7.6.2 + semver: 7.5.4 tapable: 2.2.1 typescript: 5.1.6 webpack: 5.88.2(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.17) @@ -56358,6 +56723,14 @@ snapshots: dependencies: find-index: 0.1.1 + glob@10.3.10: + dependencies: + foreground-child: 3.1.1 + jackspeak: 2.3.6 + minimatch: 9.0.4 + minipass: 7.1.1 + path-scurry: 1.10.1 + glob@10.4.1: dependencies: foreground-child: 3.1.1 @@ -56457,10 +56830,6 @@ snapshots: dependencies: type-fest: 0.20.2 - globals@13.23.0: - dependencies: - type-fest: 0.20.2 - globals@13.24.0: dependencies: type-fest: 0.20.2 @@ -57209,7 +57578,7 @@ snapshots: http-proxy@1.18.1: dependencies: eventemitter3: 4.0.7 - follow-redirects: 1.15.6(debug@4.3.4) + follow-redirects: 1.15.5 requires-port: 1.0.0 transitivePeerDependencies: - debug @@ -58066,6 +58435,12 @@ snapshots: iterare@1.2.1: {} + jackspeak@2.3.6: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + jackspeak@3.4.0: dependencies: '@isaacs/cliui': 8.0.2 @@ -58908,7 +59283,7 @@ snapshots: '@babel/core': 7.24.4 '@babel/generator': 7.24.4 '@babel/plugin-syntax-jsx': 7.22.5(@babel/core@7.24.4) - '@babel/plugin-syntax-typescript': 7.24.7(@babel/core@7.24.4) + '@babel/plugin-syntax-typescript': 7.22.5(@babel/core@7.24.4) '@babel/types': 7.24.5 '@jest/expect-utils': 29.7.0 '@jest/transform': 29.7.0 @@ -59144,6 +59519,8 @@ snapshots: jose@4.13.1: {} + jose@4.15.5: {} + joycon@3.1.1: {} js-beautify@1.14.7: @@ -59208,7 +59585,7 @@ snapshots: transitivePeerDependencies: - supports-color - jscodeshift@0.14.0(@babel/preset-env@7.24.5(@babel/core@7.24.4)): + jscodeshift@0.14.0(@babel/preset-env@7.23.2(@babel/core@7.24.4)): dependencies: '@babel/core': 7.24.4 '@babel/parser': 7.24.4 @@ -59216,7 +59593,7 @@ snapshots: '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.24.4) '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.24.4) '@babel/plugin-transform-modules-commonjs': 7.23.0(@babel/core@7.24.4) - '@babel/preset-env': 7.24.5(@babel/core@7.24.4) + '@babel/preset-env': 7.23.2(@babel/core@7.24.4) '@babel/preset-flow': 7.22.15(@babel/core@7.24.4) '@babel/preset-typescript': 7.23.2(@babel/core@7.24.4) '@babel/register': 7.21.0(@babel/core@7.24.4) @@ -59551,6 +59928,17 @@ snapshots: transitivePeerDependencies: - supports-color + jwks-rsa@3.1.0: + dependencies: + '@types/express': 4.17.17 + '@types/jsonwebtoken': 9.0.5 + debug: 4.3.4(supports-color@8.1.1) + jose: 4.15.5 + limiter: 1.1.5 + lru-memoizer: 2.2.0 + transitivePeerDependencies: + - supports-color + jws@3.2.2: dependencies: jwa: 1.4.1 @@ -59796,7 +60184,7 @@ snapshots: dependencies: copy-anything: 2.0.6 parse-node-version: 1.0.1 - tslib: 2.6.2 + tslib: 2.5.0 optionalDependencies: errno: 0.1.8 graceful-fs: 4.2.11 @@ -61909,7 +62297,7 @@ snapshots: needle@3.2.0: dependencies: - debug: 3.2.7(supports-color@8.1.1) + debug: 3.2.7(supports-color@5.5.0) iconv-lite: 0.6.3 sax: 1.2.4 transitivePeerDependencies: @@ -62236,12 +62624,12 @@ snapshots: nodemon@3.0.1: dependencies: - chokidar: 3.6.0 + chokidar: 3.5.3 debug: 3.2.7(supports-color@5.5.0) ignore-by-default: 1.0.1 minimatch: 3.1.2 pstree.remy: 1.1.8 - semver: 7.6.2 + semver: 7.5.4 simple-update-notifier: 2.0.0 supports-color: 5.5.0 touch: 3.1.0 @@ -62269,7 +62657,7 @@ snapshots: normalize-package-data@3.0.3: dependencies: hosted-git-info: 4.1.0 - is-core-module: 2.13.0 + is-core-module: 2.12.0 semver: 7.6.2 validate-npm-package-license: 3.0.4 @@ -63397,6 +63785,11 @@ snapshots: path-parse@1.0.7: {} + path-scurry@1.10.1: + dependencies: + lru-cache: 10.0.1 + minipass: 7.1.2 + path-scurry@1.11.1: dependencies: lru-cache: 10.2.2 @@ -63499,6 +63892,8 @@ snapshots: picocolors@1.0.0: {} + picocolors@1.0.1: {} + picomatch@2.3.1: {} picomatch@4.0.2: {} @@ -63695,7 +64090,7 @@ snapshots: portfinder@1.0.32: dependencies: async: 2.6.4 - debug: 3.2.7(supports-color@8.1.1) + debug: 3.2.7(supports-color@5.5.0) mkdirp: 0.5.6 transitivePeerDependencies: - supports-color @@ -63738,12 +64133,12 @@ snapshots: postcss: 8.4.31 postcss-value-parser: 4.2.0 - postcss-color-functional-notation@6.0.11(postcss@8.4.38): + postcss-color-functional-notation@6.0.14(postcss@8.4.38): dependencies: - '@csstools/css-color-parser': 2.0.2(@csstools/css-parser-algorithms@2.6.3(@csstools/css-tokenizer@2.3.1))(@csstools/css-tokenizer@2.3.1) - '@csstools/css-parser-algorithms': 2.6.3(@csstools/css-tokenizer@2.3.1) - '@csstools/css-tokenizer': 2.3.1 - '@csstools/postcss-progressive-custom-properties': 3.2.0(postcss@8.4.38) + '@csstools/css-color-parser': 2.0.4(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.38) '@csstools/utilities': 1.0.0(postcss@8.4.38) postcss: 8.4.38 @@ -63783,12 +64178,12 @@ snapshots: postcss: 8.4.38 postcss-value-parser: 4.2.0 - postcss-custom-media@10.0.6(postcss@8.4.38): + postcss-custom-media@10.0.8(postcss@8.4.38): dependencies: - '@csstools/cascade-layer-name-parser': 1.0.11(@csstools/css-parser-algorithms@2.6.3(@csstools/css-tokenizer@2.3.1))(@csstools/css-tokenizer@2.3.1) - '@csstools/css-parser-algorithms': 2.6.3(@csstools/css-tokenizer@2.3.1) - '@csstools/css-tokenizer': 2.3.1 - '@csstools/media-query-list-parser': 2.1.11(@csstools/css-parser-algorithms@2.6.3(@csstools/css-tokenizer@2.3.1))(@csstools/css-tokenizer@2.3.1) + '@csstools/cascade-layer-name-parser': 1.0.13(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/media-query-list-parser': 2.1.13(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) postcss: 8.4.38 postcss-custom-media@8.0.2(postcss@8.4.31): @@ -63801,11 +64196,11 @@ snapshots: postcss: 8.4.31 postcss-value-parser: 4.2.0 - postcss-custom-properties@13.3.10(postcss@8.4.38): + postcss-custom-properties@13.3.12(postcss@8.4.38): dependencies: - '@csstools/cascade-layer-name-parser': 1.0.11(@csstools/css-parser-algorithms@2.6.3(@csstools/css-tokenizer@2.3.1))(@csstools/css-tokenizer@2.3.1) - '@csstools/css-parser-algorithms': 2.6.3(@csstools/css-tokenizer@2.3.1) - '@csstools/css-tokenizer': 2.3.1 + '@csstools/cascade-layer-name-parser': 1.0.13(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 '@csstools/utilities': 1.0.0(postcss@8.4.38) postcss: 8.4.38 postcss-value-parser: 4.2.0 @@ -63815,13 +64210,13 @@ snapshots: postcss: 8.4.31 postcss-selector-parser: 6.0.15 - postcss-custom-selectors@7.1.10(postcss@8.4.38): + postcss-custom-selectors@7.1.12(postcss@8.4.38): dependencies: - '@csstools/cascade-layer-name-parser': 1.0.11(@csstools/css-parser-algorithms@2.6.3(@csstools/css-tokenizer@2.3.1))(@csstools/css-tokenizer@2.3.1) - '@csstools/css-parser-algorithms': 2.6.3(@csstools/css-tokenizer@2.3.1) - '@csstools/css-tokenizer': 2.3.1 + '@csstools/cascade-layer-name-parser': 1.0.13(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 postcss: 8.4.38 - postcss-selector-parser: 6.0.16 + postcss-selector-parser: 6.1.0 postcss-dir-pseudo-class@6.0.5(postcss@8.4.31): dependencies: @@ -63871,9 +64266,9 @@ snapshots: postcss: 8.4.31 postcss-value-parser: 4.2.0 - postcss-double-position-gradients@5.0.6(postcss@8.4.38): + postcss-double-position-gradients@5.0.7(postcss@8.4.38): dependencies: - '@csstools/postcss-progressive-custom-properties': 3.2.0(postcss@8.4.38) + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.38) '@csstools/utilities': 1.0.0(postcss@8.4.38) postcss: 8.4.38 postcss-value-parser: 4.2.0 @@ -63968,12 +64363,12 @@ snapshots: postcss: 8.4.31 postcss-value-parser: 4.2.0 - postcss-lab-function@6.0.16(postcss@8.4.38): + postcss-lab-function@6.0.19(postcss@8.4.38): dependencies: - '@csstools/css-color-parser': 2.0.2(@csstools/css-parser-algorithms@2.6.3(@csstools/css-tokenizer@2.3.1))(@csstools/css-tokenizer@2.3.1) - '@csstools/css-parser-algorithms': 2.6.3(@csstools/css-tokenizer@2.3.1) - '@csstools/css-tokenizer': 2.3.1 - '@csstools/postcss-progressive-custom-properties': 3.2.0(postcss@8.4.38) + '@csstools/css-color-parser': 2.0.4(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) + '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) + '@csstools/css-tokenizer': 2.4.1 + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.38) '@csstools/utilities': 1.0.0(postcss@8.4.38) postcss: 8.4.38 @@ -64067,7 +64462,7 @@ snapshots: caniuse-api: 3.0.0 cssnano-utils: 4.0.2(postcss@8.4.35) postcss: 8.4.35 - postcss-selector-parser: 6.0.15 + postcss-selector-parser: 6.0.16 postcss-merge-rules@7.0.0(postcss@8.4.38): dependencies: @@ -64104,7 +64499,7 @@ snapshots: postcss-minify-selectors@6.0.2(postcss@8.4.35): dependencies: postcss: 8.4.35 - postcss-selector-parser: 6.0.15 + postcss-selector-parser: 6.0.16 postcss-minify-selectors@7.0.0(postcss@8.4.38): dependencies: @@ -64123,11 +64518,18 @@ snapshots: dependencies: postcss: 8.4.38 + postcss-modules-local-by-default@4.0.0(postcss@8.4.38): + dependencies: + icss-utils: 5.1.0(postcss@8.4.38) + postcss: 8.4.38 + postcss-selector-parser: 6.0.15 + postcss-value-parser: 4.2.0 + postcss-modules-local-by-default@4.0.3(postcss@8.4.38): dependencies: icss-utils: 5.1.0(postcss@8.4.38) postcss: 8.4.38 - postcss-selector-parser: 6.0.16 + postcss-selector-parser: 6.0.15 postcss-value-parser: 4.2.0 postcss-modules-scope@3.0.0(postcss@8.4.38): @@ -64331,60 +64733,61 @@ snapshots: postcss-selector-not: 6.0.1(postcss@8.4.31) postcss-value-parser: 4.2.0 - postcss-preset-env@9.5.14(postcss@8.4.38): + postcss-preset-env@9.6.0(postcss@8.4.38): dependencies: '@csstools/postcss-cascade-layers': 4.0.6(postcss@8.4.38) - '@csstools/postcss-color-function': 3.0.16(postcss@8.4.38) - '@csstools/postcss-color-mix-function': 2.0.16(postcss@8.4.38) - '@csstools/postcss-exponential-functions': 1.0.7(postcss@8.4.38) + '@csstools/postcss-color-function': 3.0.19(postcss@8.4.38) + '@csstools/postcss-color-mix-function': 2.0.19(postcss@8.4.38) + '@csstools/postcss-content-alt-text': 1.0.0(postcss@8.4.38) + '@csstools/postcss-exponential-functions': 1.0.9(postcss@8.4.38) '@csstools/postcss-font-format-keywords': 3.0.2(postcss@8.4.38) - '@csstools/postcss-gamut-mapping': 1.0.9(postcss@8.4.38) - '@csstools/postcss-gradients-interpolation-method': 4.0.17(postcss@8.4.38) - '@csstools/postcss-hwb-function': 3.0.15(postcss@8.4.38) - '@csstools/postcss-ic-unit': 3.0.6(postcss@8.4.38) + '@csstools/postcss-gamut-mapping': 1.0.11(postcss@8.4.38) + '@csstools/postcss-gradients-interpolation-method': 4.0.20(postcss@8.4.38) + '@csstools/postcss-hwb-function': 3.0.18(postcss@8.4.38) + '@csstools/postcss-ic-unit': 3.0.7(postcss@8.4.38) '@csstools/postcss-initial': 1.0.1(postcss@8.4.38) '@csstools/postcss-is-pseudo-class': 4.0.8(postcss@8.4.38) - '@csstools/postcss-light-dark-function': 1.0.5(postcss@8.4.38) + '@csstools/postcss-light-dark-function': 1.0.8(postcss@8.4.38) '@csstools/postcss-logical-float-and-clear': 2.0.1(postcss@8.4.38) '@csstools/postcss-logical-overflow': 1.0.1(postcss@8.4.38) '@csstools/postcss-logical-overscroll-behavior': 1.0.1(postcss@8.4.38) '@csstools/postcss-logical-resize': 2.0.1(postcss@8.4.38) - '@csstools/postcss-logical-viewport-units': 2.0.9(postcss@8.4.38) - '@csstools/postcss-media-minmax': 1.1.6(postcss@8.4.38) - '@csstools/postcss-media-queries-aspect-ratio-number-values': 2.0.9(postcss@8.4.38) + '@csstools/postcss-logical-viewport-units': 2.0.11(postcss@8.4.38) + '@csstools/postcss-media-minmax': 1.1.8(postcss@8.4.38) + '@csstools/postcss-media-queries-aspect-ratio-number-values': 2.0.11(postcss@8.4.38) '@csstools/postcss-nested-calc': 3.0.2(postcss@8.4.38) '@csstools/postcss-normalize-display-values': 3.0.2(postcss@8.4.38) - '@csstools/postcss-oklab-function': 3.0.16(postcss@8.4.38) - '@csstools/postcss-progressive-custom-properties': 3.2.0(postcss@8.4.38) - '@csstools/postcss-relative-color-syntax': 2.0.16(postcss@8.4.38) + '@csstools/postcss-oklab-function': 3.0.19(postcss@8.4.38) + '@csstools/postcss-progressive-custom-properties': 3.3.0(postcss@8.4.38) + '@csstools/postcss-relative-color-syntax': 2.0.19(postcss@8.4.38) '@csstools/postcss-scope-pseudo-class': 3.0.1(postcss@8.4.38) - '@csstools/postcss-stepped-value-functions': 3.0.8(postcss@8.4.38) - '@csstools/postcss-text-decoration-shorthand': 3.0.6(postcss@8.4.38) - '@csstools/postcss-trigonometric-functions': 3.0.8(postcss@8.4.38) + '@csstools/postcss-stepped-value-functions': 3.0.10(postcss@8.4.38) + '@csstools/postcss-text-decoration-shorthand': 3.0.7(postcss@8.4.38) + '@csstools/postcss-trigonometric-functions': 3.0.10(postcss@8.4.38) '@csstools/postcss-unset-value': 3.0.1(postcss@8.4.38) autoprefixer: 10.4.19(postcss@8.4.38) - browserslist: 4.23.0 + browserslist: 4.23.2 css-blank-pseudo: 6.0.2(postcss@8.4.38) css-has-pseudo: 6.0.5(postcss@8.4.38) css-prefers-color-scheme: 9.0.1(postcss@8.4.38) - cssdb: 8.0.2 + cssdb: 8.1.0 postcss: 8.4.38 postcss-attribute-case-insensitive: 6.0.3(postcss@8.4.38) postcss-clamp: 4.1.0(postcss@8.4.38) - postcss-color-functional-notation: 6.0.11(postcss@8.4.38) + postcss-color-functional-notation: 6.0.14(postcss@8.4.38) postcss-color-hex-alpha: 9.0.4(postcss@8.4.38) postcss-color-rebeccapurple: 9.0.3(postcss@8.4.38) - postcss-custom-media: 10.0.6(postcss@8.4.38) - postcss-custom-properties: 13.3.10(postcss@8.4.38) - postcss-custom-selectors: 7.1.10(postcss@8.4.38) + postcss-custom-media: 10.0.8(postcss@8.4.38) + postcss-custom-properties: 13.3.12(postcss@8.4.38) + postcss-custom-selectors: 7.1.12(postcss@8.4.38) postcss-dir-pseudo-class: 8.0.1(postcss@8.4.38) - postcss-double-position-gradients: 5.0.6(postcss@8.4.38) + postcss-double-position-gradients: 5.0.7(postcss@8.4.38) postcss-focus-visible: 9.0.1(postcss@8.4.38) postcss-focus-within: 8.0.1(postcss@8.4.38) postcss-font-variant: 5.0.0(postcss@8.4.38) postcss-gap-properties: 5.0.1(postcss@8.4.38) postcss-image-set-function: 6.0.3(postcss@8.4.38) - postcss-lab-function: 6.0.16(postcss@8.4.38) + postcss-lab-function: 6.0.19(postcss@8.4.38) postcss-logical: 7.0.1(postcss@8.4.38) postcss-nesting: 12.1.5(postcss@8.4.38) postcss-opacity-percentage: 2.0.0(postcss@8.4.38) @@ -64494,7 +64897,7 @@ snapshots: dependencies: nanoid: 3.3.7 picocolors: 1.0.0 - source-map-js: 1.2.0 + source-map-js: 1.0.2 postcss@8.4.35: dependencies: @@ -65662,7 +66065,7 @@ snapshots: browserslist: 4.21.5 camelcase: 6.3.0 case-sensitive-paths-webpack-plugin: 2.4.0 - css-loader: 6.8.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.20)) + css-loader: 6.7.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.20)) css-minimizer-webpack-plugin: 3.4.1(esbuild@0.18.20)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.20)) dotenv: 10.0.0 dotenv-expand: 5.1.0 @@ -65748,7 +66151,7 @@ snapshots: browserslist: 4.21.5 camelcase: 6.3.0 case-sensitive-paths-webpack-plugin: 2.4.0 - css-loader: 6.8.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))) + css-loader: 6.7.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))) css-minimizer-webpack-plugin: 3.4.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))) dotenv: 10.0.0 dotenv-expand: 5.1.0 @@ -65867,7 +66270,7 @@ snapshots: react-textarea-autosize@8.5.3(@types/react@18.3.3)(react@18.3.1): dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.23.2 react: 18.3.1 use-composed-ref: 1.3.0(react@18.3.1) use-latest: 1.2.1(@types/react@18.3.3)(react@18.3.1) @@ -66571,7 +66974,7 @@ snapshots: rimraf@5.0.7: dependencies: - glob: 10.4.1 + glob: 10.3.10 rollup-plugin-commonjs@10.1.0(rollup@3.20.2): dependencies: @@ -66655,9 +67058,9 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.9.6 fsevents: 2.3.3 - rrdom@2.0.0-alpha.15: + rrdom@2.0.0-alpha.16: dependencies: - rrweb-snapshot: 2.0.0-alpha.15 + rrweb-snapshot: 2.0.0-alpha.16 rrule@2.7.2: dependencies: @@ -66665,7 +67068,9 @@ snapshots: rrweb-cssom@0.6.0: {} - rrweb-snapshot@2.0.0-alpha.15: {} + rrweb-snapshot@2.0.0-alpha.13: {} + + rrweb-snapshot@2.0.0-alpha.16: {} rrweb@2.0.0-alpha.13: dependencies: @@ -66675,8 +67080,8 @@ snapshots: base64-arraybuffer: 1.0.2 fflate: 0.4.8 mitt: 3.0.1 - rrdom: 2.0.0-alpha.15 - rrweb-snapshot: 2.0.0-alpha.15 + rrdom: 2.0.0-alpha.16 + rrweb-snapshot: 2.0.0-alpha.13 run-async@2.4.1: {} @@ -66784,7 +67189,7 @@ snapshots: dependencies: chokidar: 3.6.0 immutable: 4.3.0 - source-map-js: 1.2.0 + source-map-js: 1.0.2 sass@1.64.1: dependencies: @@ -67115,7 +67520,7 @@ snapshots: simple-update-notifier@2.0.0: dependencies: - semver: 7.6.2 + semver: 7.5.4 sinon@9.2.4: dependencies: @@ -67187,6 +67592,17 @@ snapshots: dependencies: no-case: 2.3.2 + snake-case@3.0.4: + dependencies: + dot-case: 3.0.4 + tslib: 2.6.2 + + snakecase-keys@5.4.4: + dependencies: + map-obj: 4.3.0 + snake-case: 3.0.4 + type-fest: 2.19.0 + snapdragon-node@2.1.1: dependencies: define-property: 1.0.0 @@ -67220,7 +67636,7 @@ snapshots: socket.io-client@4.7.2: dependencies: '@socket.io/component-emitter': 3.1.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) engine.io-client: 6.5.2 socket.io-parser: 4.2.4 transitivePeerDependencies: @@ -67296,7 +67712,7 @@ snapshots: solid-js@1.8.17: dependencies: - csstype: 3.1.2 + csstype: 3.1.3 seroval: 1.0.7 seroval-plugins: 1.0.7(seroval@1.0.7) @@ -67352,7 +67768,7 @@ snapshots: dependencies: abab: 2.0.6 iconv-lite: 0.6.3 - source-map-js: 1.2.0 + source-map-js: 1.0.2 webpack: 5.88.2(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.17) source-map-resolve@0.5.3: @@ -68064,6 +68480,23 @@ snapshots: picocolors: 1.0.0 stable: 0.1.8 + svix-fetch@3.0.0(encoding@0.1.13): + dependencies: + node-fetch: 2.7.0(encoding@0.1.13) + whatwg-fetch: 3.6.2 + transitivePeerDependencies: + - encoding + + svix@1.24.0(encoding@0.1.13): + dependencies: + '@stablelib/base64': 1.0.1 + es6-promise: 4.2.8 + fast-sha256: 1.3.0 + svix-fetch: 3.0.0(encoding@0.1.13) + url-parse: 1.5.10 + transitivePeerDependencies: + - encoding + swagger-ui-dist@4.18.2: {} swagger-ui-dist@5.11.2: {} @@ -68095,6 +68528,12 @@ snapshots: '@swc/core': 1.3.107(@swc/helpers@0.5.2) webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2)) + swr@2.2.5(react@18.3.1): + dependencies: + client-only: 0.0.1 + react: 18.3.1 + use-sync-external-store: 1.2.0(react@18.3.1) + symbol-observable@1.2.0: {} symbol-observable@4.0.0: {} @@ -68329,7 +68768,7 @@ snapshots: '@jridgewell/trace-mapping': 0.3.19 jest-worker: 27.5.1 schema-utils: 3.3.0 - serialize-javascript: 6.0.2 + serialize-javascript: 6.0.1 terser: 5.22.0 webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.20) optionalDependencies: @@ -68341,7 +68780,7 @@ snapshots: '@jridgewell/trace-mapping': 0.3.19 jest-worker: 27.5.1 schema-utils: 3.3.0 - serialize-javascript: 6.0.2 + serialize-javascript: 6.0.1 terser: 5.22.0 webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2)) optionalDependencies: @@ -68371,17 +68810,17 @@ snapshots: '@swc/core': 1.3.107(@swc/helpers@0.5.2) esbuild: 0.18.20 - terser-webpack-plugin@5.3.9(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.20.1)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.20.1)(webpack-cli@5.1.4)): + terser-webpack-plugin@5.3.9(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.21.4)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.21.4)(webpack-cli@5.1.4)): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.1 terser: 5.22.0 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.20.1)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.21.4)(webpack-cli@5.1.4) optionalDependencies: '@swc/core': 1.3.107(@swc/helpers@0.5.2) - esbuild: 0.20.1 + esbuild: 0.21.4 terser-webpack-plugin@5.3.9(@swc/core@1.3.107(@swc/helpers@0.5.2))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.82.1))): dependencies: @@ -68794,7 +69233,7 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.24.4) - ts-jest@29.1.2(@babel/core@7.24.4)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.4))(esbuild@0.20.1)(jest@29.7.0(@types/node@20.14.10)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.2))(@types/node@20.14.10)(typescript@4.9.5)))(typescript@4.9.5): + ts-jest@29.1.2(@babel/core@7.24.4)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.4))(esbuild@0.21.4)(jest@29.7.0(@types/node@20.14.10)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.2))(@types/node@20.14.10)(typescript@4.9.5)))(typescript@4.9.5): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 @@ -68810,7 +69249,7 @@ snapshots: '@babel/core': 7.24.4 '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.24.4) - esbuild: 0.20.1 + esbuild: 0.21.4 ts-jest@29.1.2(@babel/core@7.24.4)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.4))(jest@29.7.0(@types/node@20.14.10)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.2))(@types/node@20.14.10)(typescript@5.4.5)))(typescript@5.4.5): dependencies: @@ -68829,14 +69268,14 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.24.4) - ts-loader@9.4.2(typescript@4.9.5)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.20.1)(webpack-cli@5.1.4)): + ts-loader@9.4.2(typescript@4.9.5)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.21.4)(webpack-cli@5.1.4)): dependencies: chalk: 4.1.2 enhanced-resolve: 5.15.0 micromatch: 4.0.5 semver: 7.5.2 typescript: 4.9.5 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.20.1)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.21.4)(webpack-cli@5.1.4) ts-loader@9.4.2(typescript@4.9.5)(webpack@5.82.1(@swc/core@1.3.107(@swc/helpers@0.5.2))(webpack-cli@5.1.4)): dependencies: @@ -69071,15 +69510,17 @@ snapshots: tslib@2.1.0: {} + tslib@2.4.1: {} + tslib@2.5.0: {} tslib@2.6.1: {} tslib@2.6.2: {} - tsup-preset-solid@2.2.0(esbuild@0.20.1)(solid-js@1.8.17)(tsup@8.0.2(@microsoft/api-extractor@7.38.0(@types/node@20.14.10))(@swc/core@1.3.107(@swc/helpers@0.5.2))(postcss@8.4.38)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.2))(@types/node@20.14.10)(typescript@4.9.5))(typescript@4.9.5)): + tsup-preset-solid@2.2.0(esbuild@0.21.4)(solid-js@1.8.17)(tsup@8.0.2(@microsoft/api-extractor@7.38.0(@types/node@20.14.10))(@swc/core@1.3.107(@swc/helpers@0.5.2))(postcss@8.4.38)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.2))(@types/node@20.14.10)(typescript@4.9.5))(typescript@4.9.5)): dependencies: - esbuild-plugin-solid: 0.5.0(esbuild@0.20.1)(solid-js@1.8.17) + esbuild-plugin-solid: 0.5.0(esbuild@0.21.4)(solid-js@1.8.17) tsup: 8.0.2(@microsoft/api-extractor@7.38.0(@types/node@20.14.10))(@swc/core@1.3.107(@swc/helpers@0.5.2))(postcss@8.4.38)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.2))(@types/node@20.14.10)(typescript@4.9.5))(typescript@4.9.5) transitivePeerDependencies: - esbuild @@ -69548,6 +69989,12 @@ snapshots: escalade: 3.1.2 picocolors: 1.0.0 + update-browserslist-db@1.1.0(browserslist@4.23.2): + dependencies: + browserslist: 4.23.2 + escalade: 3.1.2 + picocolors: 1.0.1 + upper-case-first@1.1.2: dependencies: upper-case: 1.1.3 @@ -69773,8 +70220,6 @@ snapshots: validator@13.12.0: {} - validator@13.9.0: {} - value-or-promise@1.0.12: optional: true @@ -70272,9 +70717,9 @@ snapshots: webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0): dependencies: '@discoveryjs/json-ext': 0.5.7 - '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.20.1)(webpack-cli@5.1.4)) - '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.20.1)(webpack-cli@5.1.4)) - '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.20.1)(webpack-cli@5.1.4)) + '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.21.4)(webpack-cli@5.1.4)) + '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.21.4)(webpack-cli@5.1.4)) + '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.21.4)(webpack-cli@5.1.4)) colorette: 2.0.20 commander: 10.0.1 cross-spawn: 7.0.3 @@ -70283,7 +70728,7 @@ snapshots: import-local: 3.1.0 interpret: 3.1.1 rechoir: 0.8.0 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.20.1)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.21.4)(webpack-cli@5.1.4) webpack-merge: 5.9.0 optionalDependencies: webpack-bundle-analyzer: 4.10.1 @@ -70336,7 +70781,7 @@ snapshots: webpack-dev-middleware@6.1.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.20)): dependencies: - colorette: 2.0.20 + colorette: 2.0.19 memfs: 3.5.0 mime-types: 2.1.35 range-parser: 1.2.1 @@ -70346,7 +70791,7 @@ snapshots: webpack-dev-middleware@6.1.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.82.1))): dependencies: - colorette: 2.0.20 + colorette: 2.0.19 memfs: 3.5.0 mime-types: 2.1.35 range-parser: 1.2.1 @@ -70356,7 +70801,7 @@ snapshots: webpack-dev-middleware@6.1.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))): dependencies: - colorette: 2.0.20 + colorette: 2.0.19 memfs: 3.5.0 mime-types: 2.1.35 range-parser: 1.2.1 @@ -70366,7 +70811,7 @@ snapshots: webpack-dev-middleware@6.1.1(webpack@5.88.2(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.18.17)): dependencies: - colorette: 2.0.20 + colorette: 2.0.19 memfs: 3.5.0 mime-types: 2.1.35 range-parser: 1.2.1 @@ -70462,7 +70907,7 @@ snapshots: ansi-html-community: 0.0.8 bonjour-service: 1.1.1 chokidar: 3.6.0 - colorette: 2.0.20 + colorette: 2.0.19 compression: 1.7.4 connect-history-api-fallback: 2.0.0 default-gateway: 6.0.3 @@ -70598,7 +71043,7 @@ snapshots: - esbuild - uglify-js - webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.20.1)(webpack-cli@5.1.4): + webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.21.4)(webpack-cli@5.1.4): dependencies: '@types/eslint-scope': 3.7.4 '@types/estree': 0.0.51 @@ -70621,7 +71066,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.9(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.20.1)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.20.1)(webpack-cli@5.1.4)) + terser-webpack-plugin: 5.3.9(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.21.4)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.2))(esbuild@0.21.4)(webpack-cli@5.1.4)) watchpack: 2.4.0 webpack-sources: 3.2.3 optionalDependencies: @@ -70916,7 +71361,7 @@ snapshots: dependencies: '@apideck/better-ajv-errors': 0.3.6(ajv@8.12.0) '@babel/core': 7.24.4 - '@babel/preset-env': 7.24.5(@babel/core@7.24.4) + '@babel/preset-env': 7.23.2(@babel/core@7.24.4) '@babel/runtime': 7.24.7 '@rollup/plugin-babel': 5.3.1(@babel/core@7.24.4)(@types/babel__core@7.20.5)(rollup@2.79.1) '@rollup/plugin-node-resolve': 11.2.1(rollup@2.79.1)