1
0

Merge pull request #1095 from bigcapitalhq/fix/plaid-webhook-signature-verification

fix(server): verify Plaid webhook signatures (GHSA-g56w-g54f-whq5)
This commit is contained in:
Ahmed Bouhuolia
2026-05-17 23:04:30 +02:00
committed by GitHub
5 changed files with 209 additions and 97 deletions
+1
View File
@@ -86,6 +86,7 @@
"fp-ts": "^2.16.9", "fp-ts": "^2.16.9",
"ioredis": "^5.6.0", "ioredis": "^5.6.0",
"is-my-json-valid": "^2.20.5", "is-my-json-valid": "^2.20.5",
"jose": "^5.9.6",
"js-money": "^0.6.3", "js-money": "^0.6.3",
"knex": "^3.1.0", "knex": "^3.1.0",
"lamda": "^0.4.1", "lamda": "^0.4.1",
@@ -24,6 +24,7 @@ import { BankingPlaidWebhooksController } from './BankingPlaidWebhooks.controlle
import { SetupPlaidItemTenantService } from './command/SetupPlaidItemTenant.service'; import { SetupPlaidItemTenantService } from './command/SetupPlaidItemTenant.service';
import { UpdateBankingPlaidTransitionsQueueJob } from './types/BankingPlaid.types'; import { UpdateBankingPlaidTransitionsQueueJob } from './types/BankingPlaid.types';
import { PlaidFetchTransactionsProcessor } from './jobs/PlaidFetchTransactionsJob'; import { PlaidFetchTransactionsProcessor } from './jobs/PlaidFetchTransactionsJob';
import { PlaidWebhookVerificationService } from './PlaidWebhookVerification.service';
const models = [RegisterTenancyModel(PlaidItem)]; const models = [RegisterTenancyModel(PlaidItem)];
@@ -50,6 +51,7 @@ const models = [RegisterTenancyModel(PlaidItem)];
PlaidLinkTokenService, PlaidLinkTokenService,
PlaidApplication, PlaidApplication,
SetupPlaidItemTenantService, SetupPlaidItemTenantService,
PlaidWebhookVerificationService,
TenancyContext, TenancyContext,
PlaidFetchTransactionsProcessor, PlaidFetchTransactionsProcessor,
PlaidUpdateTransactionsOnItemCreatedSubscriber, PlaidUpdateTransactionsOnItemCreatedSubscriber,
@@ -1,31 +1,50 @@
import { Body, Controller, Post } from '@nestjs/common'; import {
import { PlaidWebhookDto } from './dtos/PlaidItem.dto'; BadRequestException,
Body,
Controller,
Headers,
HttpCode,
Logger,
Post,
RawBodyRequest,
Req,
} from '@nestjs/common';
import { Request } from 'express';
import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { PlaidWebhookDto } from './dtos/PlaidItem.dto';
import { PlaidApplication } from './PlaidApplication'; import { PlaidApplication } from './PlaidApplication';
import { PublicRoute } from '../Auth/guards/jwt.guard'; import { PublicRoute } from '../Auth/guards/jwt.guard';
import { SetupPlaidItemTenantService } from './command/SetupPlaidItemTenant.service'; import { SetupPlaidItemTenantService } from './command/SetupPlaidItemTenant.service';
import { PlaidWebhookVerificationService } from './PlaidWebhookVerification.service';
@Controller('banking/plaid') @Controller('banking/plaid')
@ApiTags('banking-plaid') @ApiTags('banking-plaid')
@PublicRoute() @PublicRoute()
export class BankingPlaidWebhooksController { export class BankingPlaidWebhooksController {
private readonly logger = new Logger(BankingPlaidWebhooksController.name);
constructor( constructor(
private readonly plaidApplication: PlaidApplication, private readonly plaidApplication: PlaidApplication,
private readonly setupPlaidItemTenantService: SetupPlaidItemTenantService, private readonly setupPlaidItemTenantService: SetupPlaidItemTenantService,
private readonly verificationService: PlaidWebhookVerificationService,
) {} ) {}
@Post('webhooks') @Post('webhooks')
@HttpCode(200)
@ApiOperation({ summary: 'Listen to Plaid webhooks' }) @ApiOperation({ summary: 'Listen to Plaid webhooks' })
webhooks(@Body() { itemId, webhookType, webhookCode }: PlaidWebhookDto) { async webhooks(
return this.setupPlaidItemTenantService.setupPlaidTenant( @Req() req: RawBodyRequest<Request>,
itemId, @Headers('plaid-verification') verification: string,
() => { @Body() { itemId, webhookType, webhookCode }: PlaidWebhookDto,
return this.plaidApplication.webhooks( ) {
itemId, try {
webhookType, await this.verificationService.verifyWebhook(req.rawBody, verification);
webhookCode, } catch (err) {
); this.logger.warn(`Plaid webhook verification failed: ${err.message}`);
}, throw new BadRequestException('Invalid Plaid webhook signature');
}
return this.setupPlaidItemTenantService.setupPlaidTenant(itemId, () =>
this.plaidApplication.webhooks(itemId, webhookType, webhookCode),
); );
} }
} }
@@ -0,0 +1,101 @@
import { createHash, timingSafeEqual } from 'crypto';
import { Inject, Injectable } from '@nestjs/common';
import {
decodeProtectedHeader,
importJWK,
jwtVerify,
type JWK,
type KeyLike,
} from 'jose';
import * as LRUCache from 'lru-cache';
import type { PlaidApi } from 'plaid';
import { PLAID_CLIENT } from '../Plaid/Plaid.module';
const ALLOWED_ALG = 'ES256';
const MAX_TOKEN_AGE = '5m';
const KEY_CACHE_MAX = 100;
const KEY_CACHE_TTL_MS = 24 * 60 * 60 * 1000;
type ImportedKey = KeyLike | Uint8Array;
@Injectable()
export class PlaidWebhookVerificationService {
private readonly keyCache: LRUCache<string, ImportedKey> = new LRUCache({
max: KEY_CACHE_MAX,
maxAge: KEY_CACHE_TTL_MS,
});
constructor(@Inject(PLAID_CLIENT) private readonly plaidClient: PlaidApi) {}
public async verifyWebhook(
rawBody: Buffer | undefined,
verificationHeader: string | undefined,
): Promise<void> {
if (!rawBody || rawBody.length === 0) {
throw new Error('Plaid webhook raw body missing');
}
if (!verificationHeader) {
throw new Error('Plaid-Verification header missing');
}
const header = decodeProtectedHeader(verificationHeader);
if (header.alg !== ALLOWED_ALG) {
throw new Error(`Unexpected webhook JWT alg: ${header.alg}`);
}
if (!header.kid) {
throw new Error('Webhook JWT missing kid header');
}
const key = await this.getVerificationKey(header.kid);
const { payload } = await jwtVerify(verificationHeader, key, {
algorithms: [ALLOWED_ALG],
maxTokenAge: MAX_TOKEN_AGE,
});
const expectedHash = payload['request_body_sha256'];
if (typeof expectedHash !== 'string') {
throw new Error('Webhook JWT missing request_body_sha256 claim');
}
const actualHash = createHash('sha256').update(rawBody).digest('hex');
if (!this.constantTimeEquals(actualHash, expectedHash)) {
throw new Error('Webhook body hash mismatch');
}
}
private async getVerificationKey(kid: string): Promise<ImportedKey> {
const cached = this.keyCache.get(kid);
if (cached) return cached;
const response = await this.plaidClient.webhookVerificationKeyGet({
key_id: kid,
});
const plaidKey = response.data.key;
if (
plaidKey.expired_at !== null &&
plaidKey.expired_at !== undefined &&
plaidKey.expired_at * 1000 < Date.now()
) {
throw new Error(`Plaid verification key ${kid} is expired`);
}
const jwk: JWK = {
kty: plaidKey.kty,
crv: plaidKey.crv,
x: plaidKey.x,
y: plaidKey.y,
alg: plaidKey.alg,
use: plaidKey.use,
kid: plaidKey.kid,
};
const imported = await importJWK(jwk, ALLOWED_ALG);
this.keyCache.set(kid, imported);
return imported;
}
private constantTimeEquals(a: string, b: string): boolean {
if (a.length !== b.length) return false;
return timingSafeEqual(Buffer.from(a, 'utf8'), Buffer.from(b, 'utf8'));
}
}
+74 -85
View File
@@ -201,6 +201,9 @@ importers:
is-my-json-valid: is-my-json-valid:
specifier: ^2.20.5 specifier: ^2.20.5
version: 2.20.6 version: 2.20.6
jose:
specifier: ^5.9.6
version: 5.10.0
js-money: js-money:
specifier: ^0.6.3 specifier: ^0.6.3
version: 0.6.3 version: 0.6.3
@@ -9337,6 +9340,9 @@ packages:
jju@1.4.0: jju@1.4.0:
resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
jose@5.10.0:
resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==}
joycon@3.1.1: joycon@3.1.1:
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
engines: {node: '>=10'} engines: {node: '>=10'}
@@ -14052,11 +14058,11 @@ snapshots:
'@babel/helpers': 7.28.4 '@babel/helpers': 7.28.4
'@babel/parser': 7.28.5 '@babel/parser': 7.28.5
'@babel/template': 7.27.2 '@babel/template': 7.27.2
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
'@babel/types': 7.28.5 '@babel/types': 7.28.5
'@jridgewell/remapping': 2.3.5 '@jridgewell/remapping': 2.3.5
convert-source-map: 2.0.0 convert-source-map: 2.0.0
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
gensync: 1.0.0-beta.2 gensync: 1.0.0-beta.2
json5: 2.2.3 json5: 2.2.3
semver: 6.3.1 semver: 6.3.1
@@ -14152,7 +14158,7 @@ snapshots:
'@babel/helper-optimise-call-expression': 7.27.1 '@babel/helper-optimise-call-expression': 7.27.1
'@babel/helper-replace-supers': 7.27.1(@babel/core@7.26.0) '@babel/helper-replace-supers': 7.27.1(@babel/core@7.26.0)
'@babel/helper-skip-transparent-expression-wrappers': 7.27.1 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
semver: 6.3.1 semver: 6.3.1
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -14165,7 +14171,7 @@ snapshots:
'@babel/helper-optimise-call-expression': 7.27.1 '@babel/helper-optimise-call-expression': 7.27.1
'@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5)
'@babel/helper-skip-transparent-expression-wrappers': 7.27.1 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
semver: 6.3.1 semver: 6.3.1
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -14189,7 +14195,7 @@ snapshots:
'@babel/core': 7.26.0 '@babel/core': 7.26.0
'@babel/helper-compilation-targets': 7.27.2 '@babel/helper-compilation-targets': 7.27.2
'@babel/helper-plugin-utils': 7.27.1 '@babel/helper-plugin-utils': 7.27.1
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
lodash.debounce: 4.0.8 lodash.debounce: 4.0.8
resolve: 1.22.8 resolve: 1.22.8
transitivePeerDependencies: transitivePeerDependencies:
@@ -14200,7 +14206,7 @@ snapshots:
'@babel/core': 7.26.0 '@babel/core': 7.26.0
'@babel/helper-compilation-targets': 7.27.2 '@babel/helper-compilation-targets': 7.27.2
'@babel/helper-plugin-utils': 7.27.1 '@babel/helper-plugin-utils': 7.27.1
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
lodash.debounce: 4.0.8 lodash.debounce: 4.0.8
resolve: 1.22.11 resolve: 1.22.11
transitivePeerDependencies: transitivePeerDependencies:
@@ -14211,7 +14217,7 @@ snapshots:
'@babel/core': 7.28.5 '@babel/core': 7.28.5
'@babel/helper-compilation-targets': 7.27.2 '@babel/helper-compilation-targets': 7.27.2
'@babel/helper-plugin-utils': 7.27.1 '@babel/helper-plugin-utils': 7.27.1
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
lodash.debounce: 4.0.8 lodash.debounce: 4.0.8
resolve: 1.22.11 resolve: 1.22.11
transitivePeerDependencies: transitivePeerDependencies:
@@ -14236,7 +14242,7 @@ snapshots:
'@babel/helper-member-expression-to-functions@7.28.5': '@babel/helper-member-expression-to-functions@7.28.5':
dependencies: dependencies:
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
'@babel/types': 7.28.5 '@babel/types': 7.28.5
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -14245,13 +14251,6 @@ snapshots:
dependencies: dependencies:
'@babel/types': 7.24.5 '@babel/types': 7.24.5
'@babel/helper-module-imports@7.25.9':
dependencies:
'@babel/traverse': 7.28.5
'@babel/types': 7.28.5
transitivePeerDependencies:
- supports-color
'@babel/helper-module-imports@7.25.9(supports-color@5.5.0)': '@babel/helper-module-imports@7.25.9(supports-color@5.5.0)':
dependencies: dependencies:
'@babel/traverse': 7.28.5(supports-color@5.5.0) '@babel/traverse': 7.28.5(supports-color@5.5.0)
@@ -14261,7 +14260,7 @@ snapshots:
'@babel/helper-module-imports@7.27.1': '@babel/helper-module-imports@7.27.1':
dependencies: dependencies:
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
'@babel/types': 7.28.5 '@babel/types': 7.28.5
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -14269,9 +14268,9 @@ snapshots:
'@babel/helper-module-transforms@7.26.0(@babel/core@7.26.0)': '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.0)':
dependencies: dependencies:
'@babel/core': 7.26.0 '@babel/core': 7.26.0
'@babel/helper-module-imports': 7.25.9 '@babel/helper-module-imports': 7.25.9(supports-color@5.5.0)
'@babel/helper-validator-identifier': 7.28.5 '@babel/helper-validator-identifier': 7.28.5
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -14280,7 +14279,7 @@ snapshots:
'@babel/core': 7.26.0 '@babel/core': 7.26.0
'@babel/helper-module-imports': 7.27.1 '@babel/helper-module-imports': 7.27.1
'@babel/helper-validator-identifier': 7.28.5 '@babel/helper-validator-identifier': 7.28.5
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -14289,7 +14288,7 @@ snapshots:
'@babel/core': 7.28.5 '@babel/core': 7.28.5
'@babel/helper-module-imports': 7.27.1 '@babel/helper-module-imports': 7.27.1
'@babel/helper-validator-identifier': 7.28.5 '@babel/helper-validator-identifier': 7.28.5
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -14308,7 +14307,7 @@ snapshots:
'@babel/core': 7.26.0 '@babel/core': 7.26.0
'@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-annotate-as-pure': 7.27.3
'@babel/helper-wrap-function': 7.28.3 '@babel/helper-wrap-function': 7.28.3
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -14317,7 +14316,7 @@ snapshots:
'@babel/core': 7.28.5 '@babel/core': 7.28.5
'@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-annotate-as-pure': 7.27.3
'@babel/helper-wrap-function': 7.28.3 '@babel/helper-wrap-function': 7.28.3
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -14340,7 +14339,7 @@ snapshots:
'@babel/core': 7.26.0 '@babel/core': 7.26.0
'@babel/helper-member-expression-to-functions': 7.28.5 '@babel/helper-member-expression-to-functions': 7.28.5
'@babel/helper-optimise-call-expression': 7.27.1 '@babel/helper-optimise-call-expression': 7.27.1
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -14349,7 +14348,7 @@ snapshots:
'@babel/core': 7.28.5 '@babel/core': 7.28.5
'@babel/helper-member-expression-to-functions': 7.28.5 '@babel/helper-member-expression-to-functions': 7.28.5
'@babel/helper-optimise-call-expression': 7.27.1 '@babel/helper-optimise-call-expression': 7.27.1
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -14359,7 +14358,7 @@ snapshots:
'@babel/helper-skip-transparent-expression-wrappers@7.27.1': '@babel/helper-skip-transparent-expression-wrappers@7.27.1':
dependencies: dependencies:
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
'@babel/types': 7.28.5 '@babel/types': 7.28.5
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -14381,7 +14380,7 @@ snapshots:
'@babel/helper-wrap-function@7.28.3': '@babel/helper-wrap-function@7.28.3':
dependencies: dependencies:
'@babel/template': 7.27.2 '@babel/template': 7.27.2
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
'@babel/types': 7.28.5 '@babel/types': 7.28.5
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -14412,7 +14411,7 @@ snapshots:
dependencies: dependencies:
'@babel/core': 7.26.0 '@babel/core': 7.26.0
'@babel/helper-plugin-utils': 7.27.1 '@babel/helper-plugin-utils': 7.27.1
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -14420,7 +14419,7 @@ snapshots:
dependencies: dependencies:
'@babel/core': 7.28.5 '@babel/core': 7.28.5
'@babel/helper-plugin-utils': 7.27.1 '@babel/helper-plugin-utils': 7.27.1
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -14466,7 +14465,7 @@ snapshots:
dependencies: dependencies:
'@babel/core': 7.26.0 '@babel/core': 7.26.0
'@babel/helper-plugin-utils': 7.27.1 '@babel/helper-plugin-utils': 7.27.1
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -14474,7 +14473,7 @@ snapshots:
dependencies: dependencies:
'@babel/core': 7.28.5 '@babel/core': 7.28.5
'@babel/helper-plugin-utils': 7.27.1 '@babel/helper-plugin-utils': 7.27.1
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -14718,7 +14717,7 @@ snapshots:
'@babel/core': 7.26.0 '@babel/core': 7.26.0
'@babel/helper-plugin-utils': 7.27.1 '@babel/helper-plugin-utils': 7.27.1
'@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.26.0) '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.26.0)
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -14727,7 +14726,7 @@ snapshots:
'@babel/core': 7.28.5 '@babel/core': 7.28.5
'@babel/helper-plugin-utils': 7.27.1 '@babel/helper-plugin-utils': 7.27.1
'@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.5) '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.5)
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -14809,7 +14808,7 @@ snapshots:
'@babel/helper-globals': 7.28.0 '@babel/helper-globals': 7.28.0
'@babel/helper-plugin-utils': 7.27.1 '@babel/helper-plugin-utils': 7.27.1
'@babel/helper-replace-supers': 7.27.1(@babel/core@7.26.0) '@babel/helper-replace-supers': 7.27.1(@babel/core@7.26.0)
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -14821,7 +14820,7 @@ snapshots:
'@babel/helper-globals': 7.28.0 '@babel/helper-globals': 7.28.0
'@babel/helper-plugin-utils': 7.27.1 '@babel/helper-plugin-utils': 7.27.1
'@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5)
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -14841,7 +14840,7 @@ snapshots:
dependencies: dependencies:
'@babel/core': 7.26.0 '@babel/core': 7.26.0
'@babel/helper-plugin-utils': 7.27.1 '@babel/helper-plugin-utils': 7.27.1
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -14849,7 +14848,7 @@ snapshots:
dependencies: dependencies:
'@babel/core': 7.28.5 '@babel/core': 7.28.5
'@babel/helper-plugin-utils': 7.27.1 '@babel/helper-plugin-utils': 7.27.1
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -14966,7 +14965,7 @@ snapshots:
'@babel/core': 7.26.0 '@babel/core': 7.26.0
'@babel/helper-compilation-targets': 7.27.2 '@babel/helper-compilation-targets': 7.27.2
'@babel/helper-plugin-utils': 7.27.1 '@babel/helper-plugin-utils': 7.27.1
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -14975,7 +14974,7 @@ snapshots:
'@babel/core': 7.28.5 '@babel/core': 7.28.5
'@babel/helper-compilation-targets': 7.27.2 '@babel/helper-compilation-targets': 7.27.2
'@babel/helper-plugin-utils': 7.27.1 '@babel/helper-plugin-utils': 7.27.1
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -15057,7 +15056,7 @@ snapshots:
'@babel/helper-module-transforms': 7.28.3(@babel/core@7.26.0) '@babel/helper-module-transforms': 7.28.3(@babel/core@7.26.0)
'@babel/helper-plugin-utils': 7.27.1 '@babel/helper-plugin-utils': 7.27.1
'@babel/helper-validator-identifier': 7.28.5 '@babel/helper-validator-identifier': 7.28.5
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -15067,7 +15066,7 @@ snapshots:
'@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5)
'@babel/helper-plugin-utils': 7.27.1 '@babel/helper-plugin-utils': 7.27.1
'@babel/helper-validator-identifier': 7.28.5 '@babel/helper-validator-identifier': 7.28.5
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -15136,7 +15135,7 @@ snapshots:
'@babel/helper-plugin-utils': 7.27.1 '@babel/helper-plugin-utils': 7.27.1
'@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.26.0) '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.26.0)
'@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.26.0) '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.26.0)
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -15147,7 +15146,7 @@ snapshots:
'@babel/helper-plugin-utils': 7.27.1 '@babel/helper-plugin-utils': 7.27.1
'@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5) '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5)
'@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.5) '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.5)
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -15357,7 +15356,7 @@ snapshots:
'@babel/plugin-transform-runtime@7.24.3(@babel/core@7.26.0)': '@babel/plugin-transform-runtime@7.24.3(@babel/core@7.26.0)':
dependencies: dependencies:
'@babel/core': 7.26.0 '@babel/core': 7.26.0
'@babel/helper-module-imports': 7.25.9 '@babel/helper-module-imports': 7.25.9(supports-color@5.5.0)
'@babel/helper-plugin-utils': 7.27.1 '@babel/helper-plugin-utils': 7.27.1
babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.26.0) babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.26.0)
babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.26.0) babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.26.0)
@@ -15748,23 +15747,11 @@ snapshots:
'@babel/parser': 7.28.5 '@babel/parser': 7.28.5
'@babel/template': 7.25.9 '@babel/template': 7.25.9
'@babel/types': 7.28.5 '@babel/types': 7.28.5
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
globals: 11.12.0 globals: 11.12.0
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@babel/traverse@7.28.5':
dependencies:
'@babel/code-frame': 7.27.1
'@babel/generator': 7.28.5
'@babel/helper-globals': 7.28.0
'@babel/parser': 7.28.5
'@babel/template': 7.27.2
'@babel/types': 7.28.5
debug: 4.4.3(supports-color@10.2.2)
transitivePeerDependencies:
- supports-color
'@babel/traverse@7.28.5(supports-color@5.5.0)': '@babel/traverse@7.28.5(supports-color@5.5.0)':
dependencies: dependencies:
'@babel/code-frame': 7.27.1 '@babel/code-frame': 7.27.1
@@ -16126,7 +16113,7 @@ snapshots:
'@emotion/babel-plugin@11.12.0': '@emotion/babel-plugin@11.12.0':
dependencies: dependencies:
'@babel/helper-module-imports': 7.25.9 '@babel/helper-module-imports': 7.25.9(supports-color@5.5.0)
'@babel/runtime': 7.24.5 '@babel/runtime': 7.24.5
'@emotion/hash': 0.9.2 '@emotion/hash': 0.9.2
'@emotion/memoize': 0.9.0 '@emotion/memoize': 0.9.0
@@ -16509,7 +16496,7 @@ snapshots:
'@eslint/config-array@0.18.0': '@eslint/config-array@0.18.0':
dependencies: dependencies:
'@eslint/object-schema': 2.1.4 '@eslint/object-schema': 2.1.4
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
minimatch: 3.1.2 minimatch: 3.1.2
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -16533,7 +16520,7 @@ snapshots:
'@eslint/eslintrc@3.1.0': '@eslint/eslintrc@3.1.0':
dependencies: dependencies:
ajv: 6.12.6 ajv: 6.12.6
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
espree: 10.2.0 espree: 10.2.0
globals: 14.0.0 globals: 14.0.0
ignore: 5.3.1 ignore: 5.3.1
@@ -19348,7 +19335,7 @@ snapshots:
dependencies: dependencies:
'@babel/generator': 7.28.5 '@babel/generator': 7.28.5
'@babel/parser': 7.28.5 '@babel/parser': 7.28.5
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
'@babel/types': 7.28.5 '@babel/types': 7.28.5
'@storybook/csf': 0.1.11 '@storybook/csf': 0.1.11
'@storybook/types': 7.2.2 '@storybook/types': 7.2.2
@@ -20508,7 +20495,7 @@ snapshots:
dependencies: dependencies:
'@typescript-eslint/typescript-estree': 5.62.0(typescript@4.9.5) '@typescript-eslint/typescript-estree': 5.62.0(typescript@4.9.5)
'@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@4.9.5) '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@4.9.5)
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
eslint: 8.57.0 eslint: 8.57.0
tsutils: 3.21.0(typescript@4.9.5) tsutils: 3.21.0(typescript@4.9.5)
optionalDependencies: optionalDependencies:
@@ -20520,7 +20507,7 @@ snapshots:
dependencies: dependencies:
'@typescript-eslint/typescript-estree': 8.11.0(typescript@5.6.3) '@typescript-eslint/typescript-estree': 8.11.0(typescript@5.6.3)
'@typescript-eslint/utils': 8.11.0(eslint@9.13.0(jiti@1.21.0))(typescript@5.6.3) '@typescript-eslint/utils': 8.11.0(eslint@9.13.0(jiti@1.21.0))(typescript@5.6.3)
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
ts-api-utils: 1.3.0(typescript@5.6.3) ts-api-utils: 1.3.0(typescript@5.6.3)
optionalDependencies: optionalDependencies:
typescript: 5.6.3 typescript: 5.6.3
@@ -20550,7 +20537,7 @@ snapshots:
dependencies: dependencies:
'@typescript-eslint/types': 5.62.0 '@typescript-eslint/types': 5.62.0
'@typescript-eslint/visitor-keys': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
globby: 11.1.0 globby: 11.1.0
is-glob: 4.0.3 is-glob: 4.0.3
semver: 7.6.3 semver: 7.6.3
@@ -20564,7 +20551,7 @@ snapshots:
dependencies: dependencies:
'@typescript-eslint/types': 5.62.0 '@typescript-eslint/types': 5.62.0
'@typescript-eslint/visitor-keys': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
globby: 11.1.0 globby: 11.1.0
is-glob: 4.0.3 is-glob: 4.0.3
semver: 7.6.3 semver: 7.6.3
@@ -20578,7 +20565,7 @@ snapshots:
dependencies: dependencies:
'@typescript-eslint/types': 8.11.0 '@typescript-eslint/types': 8.11.0
'@typescript-eslint/visitor-keys': 8.11.0 '@typescript-eslint/visitor-keys': 8.11.0
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
fast-glob: 3.3.2 fast-glob: 3.3.2
is-glob: 4.0.3 is-glob: 4.0.3
minimatch: 9.0.4 minimatch: 9.0.4
@@ -20999,13 +20986,13 @@ snapshots:
agent-base@6.0.2: agent-base@6.0.2:
dependencies: dependencies:
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
agent-base@7.1.1: agent-base@7.1.1:
dependencies: dependencies:
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -21330,7 +21317,7 @@ snapshots:
babel-plugin-emotion@10.2.2: babel-plugin-emotion@10.2.2:
dependencies: dependencies:
'@babel/helper-module-imports': 7.25.9 '@babel/helper-module-imports': 7.25.9(supports-color@5.5.0)
'@emotion/hash': 0.8.0 '@emotion/hash': 0.8.0
'@emotion/memoize': 0.7.4 '@emotion/memoize': 0.7.4
'@emotion/serialize': 0.11.16 '@emotion/serialize': 0.11.16
@@ -22592,7 +22579,7 @@ snapshots:
detect-port@1.6.1: detect-port@1.6.1:
dependencies: dependencies:
address: 1.2.2 address: 1.2.2
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -22950,7 +22937,7 @@ snapshots:
esbuild-register@3.6.0(esbuild@0.18.20): esbuild-register@3.6.0(esbuild@0.18.20):
dependencies: dependencies:
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
esbuild: 0.18.20 esbuild: 0.18.20
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -23381,7 +23368,7 @@ snapshots:
estree-to-babel@3.2.1: estree-to-babel@3.2.1:
dependencies: dependencies:
'@babel/traverse': 7.28.5 '@babel/traverse': 7.28.5(supports-color@5.5.0)
'@babel/types': 7.28.5 '@babel/types': 7.28.5
c8: 7.14.0 c8: 7.14.0
transitivePeerDependencies: transitivePeerDependencies:
@@ -24195,35 +24182,35 @@ snapshots:
dependencies: dependencies:
'@tootallnate/once': 2.0.0 '@tootallnate/once': 2.0.0
agent-base: 6.0.2 agent-base: 6.0.2
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
http-proxy-agent@7.0.2: http-proxy-agent@7.0.2:
dependencies: dependencies:
agent-base: 7.1.1 agent-base: 7.1.1
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
https-proxy-agent@4.0.0: https-proxy-agent@4.0.0:
dependencies: dependencies:
agent-base: 5.1.1 agent-base: 5.1.1
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
https-proxy-agent@5.0.1: https-proxy-agent@5.0.1:
dependencies: dependencies:
agent-base: 6.0.2 agent-base: 6.0.2
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
https-proxy-agent@7.0.4: https-proxy-agent@7.0.4:
dependencies: dependencies:
agent-base: 7.1.1 agent-base: 7.1.1
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -24410,7 +24397,7 @@ snapshots:
dependencies: dependencies:
'@ioredis/commands': 1.2.0 '@ioredis/commands': 1.2.0
cluster-key-slot: 1.1.2 cluster-key-slot: 1.1.2
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
denque: 1.5.1 denque: 1.5.1
lodash.defaults: 4.2.0 lodash.defaults: 4.2.0
lodash.flatten: 4.4.0 lodash.flatten: 4.4.0
@@ -24675,7 +24662,7 @@ snapshots:
istanbul-lib-source-maps@4.0.1: istanbul-lib-source-maps@4.0.1:
dependencies: dependencies:
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
istanbul-lib-coverage: 3.2.2 istanbul-lib-coverage: 3.2.2
source-map: 0.6.1 source-map: 0.6.1
transitivePeerDependencies: transitivePeerDependencies:
@@ -25066,6 +25053,8 @@ snapshots:
jju@1.4.0: {} jju@1.4.0: {}
jose@5.10.0: {}
joycon@3.1.1: {} joycon@3.1.1: {}
js-beautify@1.15.1: js-beautify@1.15.1:
@@ -27159,7 +27148,7 @@ snapshots:
puppeteer-core@2.1.1: puppeteer-core@2.1.1:
dependencies: dependencies:
'@types/mime-types': 2.1.4 '@types/mime-types': 2.1.4
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
extract-zip: 1.7.0 extract-zip: 1.7.0
https-proxy-agent: 4.0.0 https-proxy-agent: 4.0.0
mime: 2.6.0 mime: 2.6.0
@@ -28311,7 +28300,7 @@ snapshots:
socks-proxy-agent@7.0.0: socks-proxy-agent@7.0.0:
dependencies: dependencies:
agent-base: 6.0.2 agent-base: 6.0.2
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
socks: 2.8.3 socks: 2.8.3
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -28319,7 +28308,7 @@ snapshots:
socks-proxy-agent@8.0.3: socks-proxy-agent@8.0.3:
dependencies: dependencies:
agent-base: 7.1.1 agent-base: 7.1.1
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
socks: 2.8.3 socks: 2.8.3
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -28637,7 +28626,7 @@ snapshots:
dependencies: dependencies:
component-emitter: 1.3.1 component-emitter: 1.3.1
cookiejar: 2.1.4 cookiejar: 2.1.4
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
fast-safe-stringify: 2.1.1 fast-safe-stringify: 2.1.1
form-data: 4.0.0 form-data: 4.0.0
formidable: 3.5.2 formidable: 3.5.2
@@ -29103,7 +29092,7 @@ snapshots:
tuf-js@1.1.7: tuf-js@1.1.7:
dependencies: dependencies:
'@tufjs/models': 1.0.4 '@tufjs/models': 1.0.4
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
make-fetch-happen: 11.1.1 make-fetch-happen: 11.1.1
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -29111,7 +29100,7 @@ snapshots:
tuf-js@2.2.1: tuf-js@2.2.1:
dependencies: dependencies:
'@tufjs/models': 2.0.1 '@tufjs/models': 2.0.1
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
make-fetch-happen: 13.0.1 make-fetch-happen: 13.0.1
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -29401,7 +29390,7 @@ snapshots:
vite-node@2.1.3(@types/node@20.19.25)(less@4.2.0)(sass@1.77.2)(terser@5.31.0): vite-node@2.1.3(@types/node@20.19.25)(less@4.2.0)(sass@1.77.2)(terser@5.31.0):
dependencies: dependencies:
cac: 6.7.14 cac: 6.7.14
debug: 4.4.3(supports-color@10.2.2) debug: 4.4.3(supports-color@5.5.0)
pathe: 1.1.2 pathe: 1.1.2
vite: 5.4.10(@types/node@20.19.25)(less@4.2.0)(sass@1.77.2)(terser@5.31.0) vite: 5.4.10(@types/node@20.19.25)(less@4.2.0)(sass@1.77.2)(terser@5.31.0)
transitivePeerDependencies: transitivePeerDependencies: