From 4233f2e8754eafa97354d1c78d20fbee2c60c926 Mon Sep 17 00:00:00 2001 From: Phillip Ho Date: Wed, 25 Jun 2025 12:43:54 +0800 Subject: [PATCH] feat: add webhook producer to service-utils --- .changeset/slimy-tigers-trade.md | 5 + packages/service-utils/package.json | 1 + packages/service-utils/src/node/index.ts | 1 + packages/service-utils/src/node/usageV2.ts | 98 ++++---- .../service-utils/src/node/webhookProducer.ts | 61 +++++ pnpm-lock.yaml | 214 ++++-------------- 6 files changed, 164 insertions(+), 216 deletions(-) create mode 100644 .changeset/slimy-tigers-trade.md create mode 100644 packages/service-utils/src/node/webhookProducer.ts diff --git a/.changeset/slimy-tigers-trade.md b/.changeset/slimy-tigers-trade.md new file mode 100644 index 00000000000..703c01e9040 --- /dev/null +++ b/.changeset/slimy-tigers-trade.md @@ -0,0 +1,5 @@ +--- +"@thirdweb-dev/service-utils": minor +--- + +feat: Add webhook producer to service-utils diff --git a/packages/service-utils/package.json b/packages/service-utils/package.json index c9309f66d48..e53375c1b10 100644 --- a/packages/service-utils/package.json +++ b/packages/service-utils/package.json @@ -5,6 +5,7 @@ }, "dependencies": { "@confluentinc/kafka-javascript": "1.3.2", + "@paralleldrive/cuid2": "^2.2.2", "aws4fetch": "1.0.20", "zod": "3.25.62" }, diff --git a/packages/service-utils/src/node/index.ts b/packages/service-utils/src/node/index.ts index cb381fcd94d..d55c27de024 100644 --- a/packages/service-utils/src/node/index.ts +++ b/packages/service-utils/src/node/index.ts @@ -19,6 +19,7 @@ export * from "../core/usage.js"; export * from "../core/usageV2.js"; export * from "./kafka.js"; export * from "./usageV2.js"; +export * from "./webhookProducer.js"; type NodeServiceConfig = CoreServiceConfig; diff --git a/packages/service-utils/src/node/usageV2.ts b/packages/service-utils/src/node/usageV2.ts index 546029fcd3c..fae764cb143 100644 --- a/packages/service-utils/src/node/usageV2.ts +++ b/packages/service-utils/src/node/usageV2.ts @@ -6,48 +6,60 @@ import { } from "../core/usageV2.js"; import { KafkaProducer } from "./kafka.js"; -const TEAM_ID_PREFIX = "team_"; -const PROJECT_ID_PREFIX = "prj_"; - /** - * Creates a UsageV2Producer which opens a persistent TCP connection. - * This class is thread-safe so your service should re-use one instance. + * Creates a producer for usage events. * * Example: * ```ts - * usageV2 = new UsageV2Producer(..) - * await usageV2.sendEvents(events) - * // Non-blocking: - * // void usageV2.sendEvents(events).catch((e) => console.error(e)) + * const kafkaProducer = new KafkaProducer({...}); + * const usageV2 = new UsageV2Producer({ kafkaProducer, source: "storage" }); + * await usageV2.sendEvents(events); * ``` */ export class UsageV2Producer { private kafkaProducer: KafkaProducer; private topic: string; - constructor(config: { - /** - * A descriptive name for your service. Example: "storage-server" - */ - producerName: string; - /** - * A comma-separated list of `host[:port]` Kafka servers. - */ - kafkaServers: string; - /** - * The product where usage is coming from. - */ - source: UsageV2Source; - - username: string; - password: string; - }) { - this.kafkaProducer = new KafkaProducer({ - kafkaServers: config.kafkaServers, - password: config.password, - producerName: config.producerName, - username: config.username, - }); + constructor( + config: + | { + /** + * Shared KafkaProducer instance. + */ + kafkaProducer: KafkaProducer; + /** + * The product where usage is coming from. + */ + source: UsageV2Source; + } + | { + /** + * A descriptive name for your service. Example: "storage-server" + */ + producerName: string; + /** + * A comma-separated list of `host[:port]` Kafka servers. + * @deprecated: Instantiate and pass in `kafkaProducer` instead. + */ + kafkaServers: string; + /** + * The product where usage is coming from. + */ + source: UsageV2Source; + username: string; + password: string; + }, + ) { + if ("kafkaProducer" in config) { + this.kafkaProducer = config.kafkaProducer; + } else { + this.kafkaProducer = new KafkaProducer({ + kafkaServers: config.kafkaServers, + password: config.password, + producerName: config.producerName, + username: config.username, + }); + } this.topic = getTopicName(config.source); } @@ -61,29 +73,21 @@ export class UsageV2Producer { * @param events */ async sendEvents(events: UsageV2Event[]): Promise { - const parsedEvents = events.map((event) => ({ + const parsedEvents: UsageV2Event[] = events.map((event) => ({ ...event, // Default to now. created_at: event.created_at ?? new Date(), // Default to a generated UUID. id: event.id ?? randomUUID(), - // Remove the "prj_" prefix, if any. - project_id: event.project_id?.startsWith(PROJECT_ID_PREFIX) - ? event.project_id.slice(PROJECT_ID_PREFIX.length) + // Remove the "prj_" prefix. + project_id: event.project_id?.startsWith("prj_") + ? event.project_id.slice(4) : event.project_id, - // Remove the "team_" prefix, if any. - team_id: event.team_id.startsWith(TEAM_ID_PREFIX) - ? event.team_id.slice(TEAM_ID_PREFIX.length) + // Remove the "team_" prefix. + team_id: event.team_id.startsWith("team_") + ? event.team_id.slice(5) : event.team_id, })); await this.kafkaProducer.send(this.topic, parsedEvents); } - - /** - * Disconnects UsageV2Producer. - * Useful when shutting down the service to flush in-flight events. - */ - async disconnect() { - await this.kafkaProducer.disconnect(); - } } diff --git a/packages/service-utils/src/node/webhookProducer.ts b/packages/service-utils/src/node/webhookProducer.ts new file mode 100644 index 00000000000..c93cd5d1a2c --- /dev/null +++ b/packages/service-utils/src/node/webhookProducer.ts @@ -0,0 +1,61 @@ +import assert from "node:assert"; +import { createId } from "@paralleldrive/cuid2"; +import type { KafkaProducer } from "./kafka.js"; + +interface WebhookEvent extends Record { + id?: `evt_${string}`; + teamId: string; + projectId?: string; + createdAt?: Date; + /** + * This should match your model defined in api-server. + */ + payload: Record; +} + +/** + * Creates a producer for webhook events. + * + * Example: + * ```ts + * const kafkaProducer = new KafkaProducer({...}); + * const webhookProducer = new WebhookEventProducer({ kafkaProducer }); + * await webhookProducer.sendEvents("your.topic.name", events); + * ``` + */ +export class WebhookEventProducer { + private kafkaProducer: KafkaProducer; + + constructor(config: { kafkaProducer: KafkaProducer }) { + this.kafkaProducer = config.kafkaProducer; + } + + /** + * Emit a webhook event. + * This method may throw. To call this non-blocking: + * ```ts + * void webhookProducer.sendEvents(events).catch((e) => console.error(e)) + * ``` + */ + async sendEvents(topic: string, events: WebhookEvent[]): Promise { + const parsedEvents: WebhookEvent[] = events.map((event) => { + assert( + event.teamId.startsWith("team_"), + "teamId must start with 'team_'", + ); + assert( + !event.projectId || event.projectId.startsWith("prj_"), + "projectId must start with 'prj_'", + ); + + return { + ...event, + // Default to now. + created_at: event.createdAt ?? new Date(), + // Default to a generated UUID. + id: event.id ?? `evt_${createId()}`, + }; + }); + await this.kafkaProducer.send(topic, parsedEvents); + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 11c7bd8ed2e..e7aae982a80 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -135,7 +135,7 @@ importers: version: 0.6.19(@hyperjump/browser@1.3.1)(axios@1.9.0)(idb-keyval@6.2.2)(nprogress@0.2.0)(qrcode@1.5.4)(react@19.1.0)(tailwindcss@3.4.17)(typescript@5.8.3) '@sentry/nextjs': specifier: 9.29.0 - version: 9.29.0(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(webpack@5.99.9(esbuild@0.25.5)) + version: 9.29.0(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(webpack@5.99.9) '@shazow/whatsabi': specifier: 0.22.2 version: 0.22.2(@noble/hashes@1.8.0)(typescript@5.8.3)(zod@3.25.62) @@ -337,7 +337,7 @@ importers: version: 9.0.8(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) '@storybook/nextjs': specifier: 9.0.8 - version: 9.0.8(esbuild@0.25.5)(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(type-fest@4.41.0)(typescript@5.8.3)(webpack-hot-middleware@2.26.1)(webpack@5.99.9(esbuild@0.25.5)) + version: 9.0.8(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(type-fest@4.41.0)(typescript@5.8.3)(webpack-hot-middleware@2.26.1)(webpack@5.99.9) '@types/color': specifier: 4.2.0 version: 4.2.0 @@ -1186,6 +1186,9 @@ importers: '@confluentinc/kafka-javascript': specifier: 1.3.2 version: 1.3.2(encoding@0.1.13) + '@paralleldrive/cuid2': + specifier: ^2.2.2 + version: 2.2.2 aws4fetch: specifier: 1.0.20 version: 1.0.20 @@ -1334,7 +1337,7 @@ importers: version: 2.2.0(react-native@0.78.1(@babel/core@7.27.4)(@babel/preset-env@7.27.2(@babel/core@7.27.4))(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)) '@size-limit/preset-big-lib': specifier: 11.2.0 - version: 11.2.0(bufferutil@4.0.9)(size-limit@11.2.0)(utf-8-validate@5.0.10) + version: 11.2.0(bufferutil@4.0.9)(esbuild@0.25.5)(size-limit@11.2.0)(utf-8-validate@5.0.10) '@storybook/addon-docs': specifier: 9.0.8 version: 9.0.8(@types/react@19.1.8)(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) @@ -3429,6 +3432,7 @@ packages: '@hey-api/client-fetch@0.10.0': resolution: {integrity: sha512-C7vzj4t52qPiHCqjn1l8cRTI2p4pZCd7ViLtJDTHr5ZwI4sWOYC1tmv6bd529qqY6HFFbhGCz4TAZSwKAMJncg==} + deprecated: Starting with v0.73.0, this package is bundled directly inside @hey-api/openapi-ts. peerDependencies: '@hey-api/openapi-ts': < 2 @@ -4588,6 +4592,9 @@ packages: cpu: [x64] os: [win32] + '@paralleldrive/cuid2@2.2.2': + resolution: {integrity: sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==} + '@passwordless-id/webauthn@2.1.2': resolution: {integrity: sha512-Ahj+A3O0gP3EsLV4FRXjfhbzzP895d8CnHKmhT1hkAz1zLSBCRE/iXJsasL1kwGoriDFLJ+YtO6x1rok4SZH2g==} @@ -7530,6 +7537,7 @@ packages: '@walletconnect/modal@2.7.0': resolution: {integrity: sha512-RQVt58oJ+rwqnPcIvRFeMGKuXb9qkgSmwz4noF8JZGUym3gUAzVs+uW2NQ1Owm9XOJAV+sANrtJ+VoVq1ftElw==} + deprecated: Please follow the migration guide on https://docs.reown.com/appkit/upgrade/wcm '@walletconnect/react-native-compat@2.17.3': resolution: {integrity: sha512-lHKwXKoB0rdDH1ukxUx7o86xosWbttWIHYMZ8tgAQC1k9VH3CZZCoBcHOAAX8iBzyb0n0UP3/9zRrOcJE5nz7Q==} @@ -20776,6 +20784,10 @@ snapshots: '@oxc-resolver/binding-win32-x64-msvc@11.2.0': optional: true + '@paralleldrive/cuid2@2.2.2': + dependencies: + '@noble/hashes': 1.7.2 + '@passwordless-id/webauthn@2.1.2': {} '@paulmillr/qr@0.2.1': {} @@ -20789,21 +20801,6 @@ snapshots: dependencies: playwright: 1.53.0 - '@pmmmwh/react-refresh-webpack-plugin@0.5.16(react-refresh@0.14.2)(type-fest@4.41.0)(webpack-hot-middleware@2.26.1)(webpack@5.99.9(esbuild@0.25.5))': - dependencies: - ansi-html: 0.0.9 - core-js-pure: 3.43.0 - error-stack-parser: 2.1.4 - html-entities: 2.6.0 - loader-utils: 2.0.4 - react-refresh: 0.14.2 - schema-utils: 4.3.2 - source-map: 0.7.4 - webpack: 5.99.9(esbuild@0.25.5) - optionalDependencies: - type-fest: 4.41.0 - webpack-hot-middleware: 2.26.1 - '@pmmmwh/react-refresh-webpack-plugin@0.5.16(react-refresh@0.14.2)(type-fest@4.41.0)(webpack-hot-middleware@2.26.1)(webpack@5.99.9)': dependencies: ansi-html: 0.0.9 @@ -23141,7 +23138,7 @@ snapshots: '@sentry/core@9.29.0': {} - '@sentry/nextjs@9.29.0(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(webpack@5.99.9(esbuild@0.25.5))': + '@sentry/nextjs@9.29.0(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(webpack@5.99.9)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/semantic-conventions': 1.34.0 @@ -23152,7 +23149,7 @@ snapshots: '@sentry/opentelemetry': 9.29.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.34.0) '@sentry/react': 9.29.0(react@19.1.0) '@sentry/vercel-edge': 9.29.0 - '@sentry/webpack-plugin': 3.5.0(encoding@0.1.13)(webpack@5.99.9(esbuild@0.25.5)) + '@sentry/webpack-plugin': 3.5.0(encoding@0.1.13)(webpack@5.99.9) chalk: 3.0.0 next: 15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) resolve: 1.22.8 @@ -23229,12 +23226,12 @@ snapshots: '@opentelemetry/api': 1.9.0 '@sentry/core': 9.29.0 - '@sentry/webpack-plugin@3.5.0(encoding@0.1.13)(webpack@5.99.9(esbuild@0.25.5))': + '@sentry/webpack-plugin@3.5.0(encoding@0.1.13)(webpack@5.99.9)': dependencies: '@sentry/bundler-plugin-core': 3.5.0(encoding@0.1.13) unplugin: 1.0.1 uuid: 9.0.1 - webpack: 5.99.9(esbuild@0.25.5) + webpack: 5.99.9 transitivePeerDependencies: - encoding - supports-color @@ -23327,11 +23324,11 @@ snapshots: dependencies: size-limit: 11.2.0 - '@size-limit/preset-big-lib@11.2.0(bufferutil@4.0.9)(size-limit@11.2.0)(utf-8-validate@5.0.10)': + '@size-limit/preset-big-lib@11.2.0(bufferutil@4.0.9)(esbuild@0.25.5)(size-limit@11.2.0)(utf-8-validate@5.0.10)': dependencies: '@size-limit/file': 11.2.0(size-limit@11.2.0) '@size-limit/time': 11.2.0(bufferutil@4.0.9)(size-limit@11.2.0)(utf-8-validate@5.0.10) - '@size-limit/webpack': 11.2.0(size-limit@11.2.0) + '@size-limit/webpack': 11.2.0(esbuild@0.25.5)(size-limit@11.2.0) size-limit: 11.2.0 transitivePeerDependencies: - '@swc/core' @@ -23353,11 +23350,11 @@ snapshots: - supports-color - utf-8-validate - '@size-limit/webpack@11.2.0(size-limit@11.2.0)': + '@size-limit/webpack@11.2.0(esbuild@0.25.5)(size-limit@11.2.0)': dependencies: nanoid: 5.1.5 size-limit: 11.2.0 - webpack: 5.99.9 + webpack: 5.99.9(esbuild@0.25.5) transitivePeerDependencies: - '@swc/core' - esbuild @@ -24077,22 +24074,22 @@ snapshots: ts-dedent: 2.2.0 vite: 6.3.5(@types/node@24.0.3)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(tsx@4.20.1)(yaml@2.8.0) - '@storybook/builder-webpack5@9.0.8(esbuild@0.25.5)(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3)': + '@storybook/builder-webpack5@9.0.8(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3)': dependencies: '@storybook/core-webpack': 9.0.8(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) case-sensitive-paths-webpack-plugin: 2.4.0 cjs-module-lexer: 1.4.3 - css-loader: 6.11.0(webpack@5.99.9(esbuild@0.25.5)) + css-loader: 6.11.0(webpack@5.99.9) es-module-lexer: 1.7.0 - fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.8.3)(webpack@5.99.9(esbuild@0.25.5)) - html-webpack-plugin: 5.6.3(webpack@5.99.9(esbuild@0.25.5)) + fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.8.3)(webpack@5.99.9) + html-webpack-plugin: 5.6.3(webpack@5.99.9) magic-string: 0.30.17 storybook: 9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - style-loader: 3.3.4(webpack@5.99.9(esbuild@0.25.5)) - terser-webpack-plugin: 5.3.14(esbuild@0.25.5)(webpack@5.99.9(esbuild@0.25.5)) + style-loader: 3.3.4(webpack@5.99.9) + terser-webpack-plugin: 5.3.14(webpack@5.99.9) ts-dedent: 2.2.0 - webpack: 5.99.9(esbuild@0.25.5) - webpack-dev-middleware: 6.1.3(webpack@5.99.9(esbuild@0.25.5)) + webpack: 5.99.9 + webpack-dev-middleware: 6.1.3(webpack@5.99.9) webpack-hot-middleware: 2.26.1 webpack-virtual-modules: 0.6.2 optionalDependencies: @@ -24158,7 +24155,7 @@ snapshots: react: 19.1.0 react-dom: 19.1.0(react@19.1.0) - '@storybook/nextjs@9.0.8(esbuild@0.25.5)(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(type-fest@4.41.0)(typescript@5.8.3)(webpack-hot-middleware@2.26.1)(webpack@5.99.9(esbuild@0.25.5))': + '@storybook/nextjs@9.0.8(next@15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(type-fest@4.41.0)(typescript@5.8.3)(webpack-hot-middleware@2.26.1)(webpack@5.99.9)': dependencies: '@babel/core': 7.27.4 '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.27.4) @@ -24173,33 +24170,33 @@ snapshots: '@babel/preset-react': 7.27.1(@babel/core@7.27.4) '@babel/preset-typescript': 7.27.1(@babel/core@7.27.4) '@babel/runtime': 7.27.6 - '@pmmmwh/react-refresh-webpack-plugin': 0.5.16(react-refresh@0.14.2)(type-fest@4.41.0)(webpack-hot-middleware@2.26.1)(webpack@5.99.9(esbuild@0.25.5)) - '@storybook/builder-webpack5': 9.0.8(esbuild@0.25.5)(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3) - '@storybook/preset-react-webpack': 9.0.8(esbuild@0.25.5)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.16(react-refresh@0.14.2)(type-fest@4.41.0)(webpack-hot-middleware@2.26.1)(webpack@5.99.9) + '@storybook/builder-webpack5': 9.0.8(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3) + '@storybook/preset-react-webpack': 9.0.8(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3) '@storybook/react': 9.0.8(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3) '@types/semver': 7.7.0 - babel-loader: 9.2.1(@babel/core@7.27.4)(webpack@5.99.9(esbuild@0.25.5)) - css-loader: 6.11.0(webpack@5.99.9(esbuild@0.25.5)) + babel-loader: 9.2.1(@babel/core@7.27.4)(webpack@5.99.9) + css-loader: 6.11.0(webpack@5.99.9) image-size: 2.0.2 loader-utils: 3.3.1 next: 15.3.3(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - node-polyfill-webpack-plugin: 2.0.1(webpack@5.99.9(esbuild@0.25.5)) + node-polyfill-webpack-plugin: 2.0.1(webpack@5.99.9) postcss: 8.5.5 - postcss-loader: 8.1.1(postcss@8.5.5)(typescript@5.8.3)(webpack@5.99.9(esbuild@0.25.5)) + postcss-loader: 8.1.1(postcss@8.5.5)(typescript@5.8.3)(webpack@5.99.9) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) react-refresh: 0.14.2 resolve-url-loader: 5.0.0 - sass-loader: 14.2.1(webpack@5.99.9(esbuild@0.25.5)) + sass-loader: 14.2.1(webpack@5.99.9) semver: 7.7.2 storybook: 9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) - style-loader: 3.3.4(webpack@5.99.9(esbuild@0.25.5)) + style-loader: 3.3.4(webpack@5.99.9) styled-jsx: 5.1.7(@babel/core@7.27.4)(react@19.1.0) tsconfig-paths: 4.2.0 tsconfig-paths-webpack-plugin: 4.2.0 optionalDependencies: typescript: 5.8.3 - webpack: 5.99.9(esbuild@0.25.5) + webpack: 5.99.9 transitivePeerDependencies: - '@rspack/core' - '@swc/core' @@ -24278,10 +24275,10 @@ snapshots: - webpack-hot-middleware - webpack-plugin-serve - '@storybook/preset-react-webpack@9.0.8(esbuild@0.25.5)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3)': + '@storybook/preset-react-webpack@9.0.8(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(typescript@5.8.3)': dependencies: '@storybook/core-webpack': 9.0.8(storybook@9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10)) - '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.99.9(esbuild@0.25.5)) + '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.99.9) '@types/semver': 7.7.0 find-up: 5.0.0 magic-string: 0.30.17 @@ -24292,7 +24289,7 @@ snapshots: semver: 7.7.2 storybook: 9.0.8(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10) tsconfig-paths: 4.2.0 - webpack: 5.99.9(esbuild@0.25.5) + webpack: 5.99.9 optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: @@ -24326,20 +24323,6 @@ snapshots: - uglify-js - webpack-cli - '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.99.9(esbuild@0.25.5))': - dependencies: - debug: 4.4.1(supports-color@8.1.1) - endent: 2.1.0 - find-cache-dir: 3.3.2 - flat-cache: 3.2.0 - micromatch: 4.0.8 - react-docgen-typescript: 2.4.0(typescript@5.8.3) - tslib: 2.8.1 - typescript: 5.8.3 - webpack: 5.99.9(esbuild@0.25.5) - transitivePeerDependencies: - - supports-color - '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.99.9)': dependencies: debug: 4.4.1(supports-color@8.1.1) @@ -27421,13 +27404,6 @@ snapshots: transitivePeerDependencies: - supports-color - babel-loader@9.2.1(@babel/core@7.27.4)(webpack@5.99.9(esbuild@0.25.5)): - dependencies: - '@babel/core': 7.27.4 - find-cache-dir: 4.0.0 - schema-utils: 4.3.2 - webpack: 5.99.9(esbuild@0.25.5) - babel-loader@9.2.1(@babel/core@7.27.4)(webpack@5.99.9): dependencies: '@babel/core': 7.27.4 @@ -28438,19 +28414,6 @@ snapshots: css-gradient-parser@0.0.16: {} - css-loader@6.11.0(webpack@5.99.9(esbuild@0.25.5)): - dependencies: - icss-utils: 5.1.0(postcss@8.5.5) - postcss: 8.5.5 - postcss-modules-extract-imports: 3.1.0(postcss@8.5.5) - postcss-modules-local-by-default: 4.2.0(postcss@8.5.5) - postcss-modules-scope: 3.2.1(postcss@8.5.5) - postcss-modules-values: 4.0.0(postcss@8.5.5) - postcss-value-parser: 4.2.0 - semver: 7.7.2 - optionalDependencies: - webpack: 5.99.9(esbuild@0.25.5) - css-loader@6.11.0(webpack@5.99.9): dependencies: icss-utils: 5.1.0(postcss@8.5.5) @@ -29997,23 +29960,6 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - fork-ts-checker-webpack-plugin@8.0.0(typescript@5.8.3)(webpack@5.99.9(esbuild@0.25.5)): - dependencies: - '@babel/code-frame': 7.27.1 - chalk: 4.1.2 - chokidar: 3.6.0 - cosmiconfig: 7.1.0 - deepmerge: 4.3.1 - fs-extra: 10.1.0 - memfs: 3.5.3 - minimatch: 3.1.2 - node-abort-controller: 3.1.1 - schema-utils: 3.3.0 - semver: 7.7.2 - tapable: 2.2.2 - typescript: 5.8.3 - webpack: 5.99.9(esbuild@0.25.5) - fork-ts-checker-webpack-plugin@8.0.0(typescript@5.8.3)(webpack@5.99.9): dependencies: '@babel/code-frame': 7.27.1 @@ -30616,16 +30562,6 @@ snapshots: html-void-elements@3.0.0: {} - html-webpack-plugin@5.6.3(webpack@5.99.9(esbuild@0.25.5)): - dependencies: - '@types/html-minifier-terser': 6.1.0 - html-minifier-terser: 6.1.0 - lodash: 4.17.21 - pretty-error: 4.0.0 - tapable: 2.2.2 - optionalDependencies: - webpack: 5.99.9(esbuild@0.25.5) - html-webpack-plugin@5.6.3(webpack@5.99.9): dependencies: '@types/html-minifier-terser': 6.1.0 @@ -32774,35 +32710,6 @@ snapshots: node-int64@0.4.0: {} - node-polyfill-webpack-plugin@2.0.1(webpack@5.99.9(esbuild@0.25.5)): - dependencies: - assert: 2.1.0 - browserify-zlib: 0.2.0 - buffer: 6.0.3 - console-browserify: 1.2.0 - constants-browserify: 1.0.0 - crypto-browserify: 3.12.1 - domain-browser: 4.23.0 - events: 3.3.0 - filter-obj: 2.0.2 - https-browserify: 1.0.0 - os-browserify: 0.3.0 - path-browserify: 1.0.1 - process: 0.11.10 - punycode: 2.3.1 - querystring-es3: 0.2.1 - readable-stream: 4.7.0 - stream-browserify: 3.0.0 - stream-http: 3.2.0 - string_decoder: 1.3.0 - timers-browserify: 2.0.12 - tty-browserify: 0.0.1 - type-fest: 2.19.0 - url: 0.11.4 - util: 0.12.5 - vm-browserify: 1.1.2 - webpack: 5.99.9(esbuild@0.25.5) - node-polyfill-webpack-plugin@2.0.1(webpack@5.99.9): dependencies: assert: 2.1.0 @@ -33612,17 +33519,6 @@ snapshots: tsx: 4.20.1 yaml: 2.8.0 - postcss-loader@8.1.1(postcss@8.5.5)(typescript@5.8.3)(webpack@5.99.9(esbuild@0.25.5)): - dependencies: - cosmiconfig: 9.0.0(typescript@5.8.3) - jiti: 1.21.7 - postcss: 8.5.5 - semver: 7.7.2 - optionalDependencies: - webpack: 5.99.9(esbuild@0.25.5) - transitivePeerDependencies: - - typescript - postcss-loader@8.1.1(postcss@8.5.5)(typescript@5.8.3)(webpack@5.99.9): dependencies: cosmiconfig: 9.0.0(typescript@5.8.3) @@ -34824,12 +34720,6 @@ snapshots: safer-buffer@2.1.2: {} - sass-loader@14.2.1(webpack@5.99.9(esbuild@0.25.5)): - dependencies: - neo-async: 2.6.2 - optionalDependencies: - webpack: 5.99.9(esbuild@0.25.5) - sass-loader@14.2.1(webpack@5.99.9): dependencies: neo-async: 2.6.2 @@ -35499,10 +35389,6 @@ snapshots: structured-headers@0.4.1: {} - style-loader@3.3.4(webpack@5.99.9(esbuild@0.25.5)): - dependencies: - webpack: 5.99.9(esbuild@0.25.5) - style-loader@3.3.4(webpack@5.99.9): dependencies: webpack: 5.99.9 @@ -36901,16 +36787,6 @@ snapshots: - bufferutil - utf-8-validate - webpack-dev-middleware@6.1.3(webpack@5.99.9(esbuild@0.25.5)): - dependencies: - colorette: 2.0.20 - memfs: 3.5.3 - mime-types: 2.1.35 - range-parser: 1.2.1 - schema-utils: 4.3.2 - optionalDependencies: - webpack: 5.99.9(esbuild@0.25.5) - webpack-dev-middleware@6.1.3(webpack@5.99.9): dependencies: colorette: 2.0.20