diff --git a/apps/app/languine.lock b/apps/app/languine.lock
index 692e9e463e..5b9b66c732 100644
--- a/apps/app/languine.lock
+++ b/apps/app/languine.lock
@@ -9,6 +9,10 @@ files:
languages.fr: ad225f707802ba118c22987186dd38e8
languages.no: da550ca06bcacbd30b7c6ed32c864c70
languages.pt: 30e32c7c4cf434e9c75e60c14c442541
+ common.notifications.inbox: 3882d32c66e7e768145ecd8f104b0c08
+ common.notifications.archive: e727b00944f81e1d0a95c12886ac4641
+ common.notifications.archive_all: 449e2fbab2a05e2f9f3cc1717f58eee0
+ common.notifications.no_notifications: bb76b111a28211312083c68b2efabae7
common.actions.save: c9cc8cce247e49bae79f15173ce97354
common.actions.edit: 7dce122004969d56ae2e0245cb754d35
common.actions.delete: f2a6c498fb90ee345d997f888fce3b18
diff --git a/apps/app/package.json b/apps/app/package.json
index fc0b1a0b86..129ead548a 100644
--- a/apps/app/package.json
+++ b/apps/app/package.json
@@ -19,6 +19,7 @@
"@nangohq/frontend": "^0.48.4",
"@nangohq/node": "^0.48.4",
"@novu/headless": "^2.0.4",
+ "@novu/react": "^2.6.5",
"@prisma/instrumentation": "^6.3.0",
"@tanstack/react-query": "^5.66.0",
"@tanstack/react-table": "^8.20.6",
@@ -86,6 +87,7 @@
},
"devDependencies": {
"@bubba/db": "workspace:*",
+ "@bubba/notifications": "workspace:*",
"@trigger.dev/build": "3.3.13",
"@types/node": "^22.13.0",
"@types/react": "^19.0.8",
diff --git a/apps/app/src/components/header.tsx b/apps/app/src/components/header.tsx
index dba9fe73ee..66d085c55a 100644
--- a/apps/app/src/components/header.tsx
+++ b/apps/app/src/components/header.tsx
@@ -3,11 +3,14 @@ import { getI18n } from "@/locales/server";
import { Button } from "@bubba/ui/button";
import { Icons } from "@bubba/ui/icons";
import { Skeleton } from "@bubba/ui/skeleton";
+import { Inbox } from "@novu/react";
+import { useSession } from "next-auth/react";
import Link from "next/link";
import { Suspense } from "react";
import { AssistantButton } from "./assistant/button";
import { FeedbackForm } from "./feedback-form";
import { MobileMenu } from "./mobile-menu";
+import { NotificationCenter } from "./notification-center";
export async function Header() {
const t = await getI18n();
@@ -38,6 +41,9 @@ export async function Header() {
+
+
+
}>
diff --git a/apps/app/src/components/notification-center.tsx b/apps/app/src/components/notification-center.tsx
new file mode 100644
index 0000000000..2a264153c3
--- /dev/null
+++ b/apps/app/src/components/notification-center.tsx
@@ -0,0 +1,230 @@
+"use client";
+
+import { useNotifications } from "@/hooks/use-notifications";
+import { useI18n } from "@/locales/client";
+import { Button } from "@bubba/ui/button";
+import { Icons } from "@bubba/ui/icons";
+import { Popover, PopoverContent, PopoverTrigger } from "@bubba/ui/popover";
+import { ScrollArea } from "@bubba/ui/scroll-area";
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@bubba/ui/tabs";
+import { formatDistanceToNow } from "date-fns";
+import Link from "next/link";
+import { useEffect, useState } from "react";
+
+function EmptyState({ description }: { description: string }) {
+ return (
+
+ );
+}
+
+function NotificationItem({
+ id,
+ setOpen,
+ description,
+ createdAt,
+ recordId,
+ from,
+ to,
+ markMessageAsRead,
+ type,
+}: {
+ id: string;
+ setOpen: (open: boolean) => void;
+ description: string;
+ createdAt: string;
+ recordId: string;
+ from: string;
+ to: string;
+ markMessageAsRead: (id: string) => void;
+ type: string;
+}) {
+ switch (type) {
+ case "inapp_task_reminder":
+ return (
+
+
setOpen(false)}
+ href={`/tasks/${recordId}`}
+ >
+
+
+
{description}
+
+ {formatDistanceToNow(new Date(createdAt))} ago
+
+
+
+ {markMessageAsRead && (
+
+
+
+ )}
+
+ );
+ default:
+ return null;
+ }
+}
+
+export function NotificationCenter() {
+ const t = useI18n();
+
+ const [isOpen, setOpen] = useState(false);
+ const {
+ hasUnseenNotifications,
+ notifications,
+ markMessageAsRead,
+ markAllMessagesAsSeen,
+ markAllMessagesAsRead,
+ } = useNotifications();
+
+ const unreadNotifications = notifications.filter(
+ (notification) => !notification.read,
+ );
+
+ const archivedNotifications = notifications.filter(
+ (notification) => notification.read,
+ );
+
+ useEffect(() => {
+ if (isOpen && hasUnseenNotifications) {
+ markAllMessagesAsSeen();
+ }
+ }, [hasUnseenNotifications, isOpen]);
+
+ return (
+
+
+
+
+
+
+
+
+ {t("common.notifications.inbox")}
+
+
+ {t("common.notifications.archive")}
+
+
+
+
+
+
+
+
+ {!unreadNotifications.length && (
+
+ )}
+
+ {unreadNotifications.length > 0 && (
+
+
+ {unreadNotifications.map((notification) => {
+ return (
+
+ );
+ })}
+
+
+ )}
+
+ {unreadNotifications.length > 0 && (
+
+
+
+ )}
+
+
+
+ {!archivedNotifications.length && (
+
+ )}
+
+ {archivedNotifications.length > 0 && (
+
+
+ {archivedNotifications.map((notification) => {
+ return (
+
+ );
+ })}
+
+
+ )}
+
+
+
+
+ );
+}
diff --git a/apps/app/src/env.mjs b/apps/app/src/env.mjs
index 4ff1d6de13..7273fdb6fb 100644
--- a/apps/app/src/env.mjs
+++ b/apps/app/src/env.mjs
@@ -26,6 +26,7 @@ export const env = createEnv({
NEXT_PUBLIC_POSTHOG_KEY: z.string().optional(),
NEXT_PUBLIC_POSTHOG_HOST: z.string().optional(),
NEXT_PUBLIC_VERCEL_URL: z.string().optional(),
+ NEXT_PUBLIC_NOVU_IDENTIFIER: z.string().optional(),
},
runtimeEnv: {
@@ -49,6 +50,7 @@ export const env = createEnv({
VERCEL_TEAM_ID: process.env.VERCEL_TEAM_ID,
VERCEL_PROJECT_ID: process.env.VERCEL_PROJECT_ID,
NEXT_PUBLIC_VERCEL_URL: process.env.NEXT_PUBLIC_VERCEL_URL,
+ NEXT_PUBLIC_NOVU_IDENTIFIER: process.env.NEXT_PUBLIC_NOVU_IDENTIFIER,
},
skipValidation: !!process.env.CI || !!process.env.SKIP_ENV_VALIDATION,
diff --git a/apps/app/src/hooks/use-notifications.ts b/apps/app/src/hooks/use-notifications.ts
new file mode 100644
index 0000000000..b40ab78931
--- /dev/null
+++ b/apps/app/src/hooks/use-notifications.ts
@@ -0,0 +1,164 @@
+import { env } from "@/env.mjs";
+import { HeadlessService, type IMessage } from "@novu/headless";
+import { useSession } from "next-auth/react";
+import { useCallback, useEffect, useRef, useState } from "react";
+
+interface Notification {
+ id: string;
+ read: boolean;
+ seen: boolean;
+ createdAt: string;
+ payload: {
+ description: string;
+ recordId: string;
+ type: string;
+ from: string;
+ to: string;
+ }
+}
+
+export function useNotifications() {
+ const [isLoading, setLoading] = useState(true);
+ const [notifications, setNotifications] = useState([]);
+ const [subscriberId, setSubscriberId] = useState();
+ const headlessServiceRef = useRef(null);
+ const { data: session } = useSession();
+
+ const markAllMessagesAsRead = () => {
+ const headlessService = headlessServiceRef.current;
+
+ if (headlessService) {
+ setNotifications((prevNotifications) =>
+ prevNotifications.map((notification) => {
+ return {
+ ...notification,
+ read: true,
+ };
+ }),
+ );
+
+ headlessService.markAllMessagesAsRead({
+ listener: () => { },
+ onError: () => { },
+ });
+ }
+ };
+
+ const markMessageAsRead = (messageId: string) => {
+ const headlessService = headlessServiceRef.current;
+
+ if (headlessService) {
+ setNotifications((prevNotifications) =>
+ prevNotifications.map((notification) => {
+ if (notification.id === messageId) {
+ return {
+ ...notification,
+ read: true,
+ };
+ }
+
+ return notification;
+ }),
+ );
+
+ headlessService.markNotificationsAsRead({
+ messageId: [messageId],
+ listener: (result) => { },
+ onError: (error) => { },
+ });
+ }
+ };
+
+ const fetchNotifications = useCallback(() => {
+ const headlessService = headlessServiceRef.current;
+
+ if (headlessService) {
+ headlessService.fetchNotifications({
+ listener: () => { },
+ onSuccess: (response) => {
+ setLoading(false);
+ setNotifications(
+ response.data.map((msg: IMessage) => ({
+ id: msg._id,
+ read: msg.read,
+ seen: msg.seen,
+ createdAt: msg.createdAt,
+ payload: {
+ description: msg.payload.description as string,
+ recordId: msg.payload.recordId as string,
+ type: msg.payload.type as string,
+ from: msg.payload.from as string,
+ to: msg.payload.to as string,
+ }
+ }))
+ );
+ },
+ });
+ }
+ }, []);
+
+ const markAllMessagesAsSeen = () => {
+ const headlessService = headlessServiceRef.current;
+
+ if (headlessService) {
+ setNotifications((prevNotifications) =>
+ prevNotifications.map((notification) => ({
+ ...notification,
+ seen: true,
+ })),
+ );
+ headlessService.markAllMessagesAsSeen({
+ listener: () => { },
+ onError: () => { },
+ });
+ }
+ };
+
+ useEffect(() => {
+ if (session?.user) {
+ setSubscriberId(`${session.user.organizationId}_${session.user.id}`);
+ }
+ }, [session]);
+
+ useEffect(() => {
+ const headlessService = headlessServiceRef.current;
+
+ if (headlessService) {
+ headlessService.listenNotificationReceive({
+ listener: () => {
+ fetchNotifications();
+ }
+ });
+ }
+ }, [headlessServiceRef.current]);
+
+ useEffect(() => {
+ if (subscriberId && !headlessServiceRef.current) {
+ const headlessService = new HeadlessService({
+ applicationIdentifier: env.NEXT_PUBLIC_NOVU_IDENTIFIER!,
+ subscriberId,
+ });
+
+ headlessService.initializeSession({
+ listener: () => { },
+ onSuccess: () => {
+ console.log('Novu session initialized successfully');
+ headlessServiceRef.current = headlessService;
+ fetchNotifications();
+ },
+ onError: (error) => {
+ console.error('Failed to initialize Novu session:', error);
+ },
+ });
+ }
+ }, [fetchNotifications, subscriberId]);
+
+ return {
+ isLoading,
+ markAllMessagesAsRead,
+ markMessageAsRead,
+ markAllMessagesAsSeen,
+ hasUnseenNotifications: notifications.some((notification) => !notification.seen),
+ notifications,
+ };
+}
diff --git a/apps/app/src/jobs/tasks/organization/new-organization.ts b/apps/app/src/jobs/tasks/organization/new-organization.ts
index 5886f5d94b..e52c79a7af 100644
--- a/apps/app/src/jobs/tasks/organization/new-organization.ts
+++ b/apps/app/src/jobs/tasks/organization/new-organization.ts
@@ -1,13 +1,11 @@
-import { soc2Seed } from "@/actions/soc2-seed";
import { logger, schemaTask } from "@trigger.dev/sdk/v3";
import { z } from "zod";
-import createDefaultPoliciesTask from "./create-default-policies";
export const newOrganizationTask = schemaTask({
id: "new-organization",
schema: z.object({
- organizationId: z.string().uuid(),
- userId: z.string().uuid(),
+ organizationId: z.string(),
+ userId: z.string()
}),
run: async ({ organizationId, userId }) => {
logger.info("New organization task started", {
diff --git a/apps/app/src/locales/en.ts b/apps/app/src/locales/en.ts
index 487862eae3..fc7ff06208 100644
--- a/apps/app/src/locales/en.ts
+++ b/apps/app/src/locales/en.ts
@@ -12,6 +12,12 @@ export default {
pt: "Portuguese",
},
common: {
+ notifications: {
+ inbox: "Inbox",
+ archive: "Archive",
+ archive_all: "Archive all",
+ no_notifications: "No new notifications",
+ },
actions: {
save: "Save",
edit: "Edit",
diff --git a/apps/app/src/locales/es.ts b/apps/app/src/locales/es.ts
index a52f3dca21..681a41230c 100644
--- a/apps/app/src/locales/es.ts
+++ b/apps/app/src/locales/es.ts
@@ -136,6 +136,12 @@ export default {
uploading_files: "Subiendo {target}...",
remove_file: "Eliminar archivo"
}
+ },
+ notifications: {
+ inbox: "Bandeja de entrada",
+ archive: "Archivo",
+ archive_all: "Archivar todo",
+ no_notifications: "No hay nuevas notificaciones"
}
},
header: {
diff --git a/apps/app/src/locales/fr.ts b/apps/app/src/locales/fr.ts
index 0b9ffbc967..41a6add479 100644
--- a/apps/app/src/locales/fr.ts
+++ b/apps/app/src/locales/fr.ts
@@ -136,6 +136,12 @@ export default {
uploading_files: "Téléchargement de {target}...",
remove_file: "Supprimer le fichier"
}
+ },
+ notifications: {
+ inbox: "Boîte de réception",
+ archive: "Archive",
+ archive_all: "Archiver tout",
+ no_notifications: "Aucune nouvelle notification"
}
},
header: {
diff --git a/apps/app/src/locales/no.ts b/apps/app/src/locales/no.ts
index 43f0677812..c781c98700 100644
--- a/apps/app/src/locales/no.ts
+++ b/apps/app/src/locales/no.ts
@@ -136,6 +136,12 @@ export default {
uploading_files: "Laster opp {target}...",
remove_file: "Fjern fil"
}
+ },
+ notifications: {
+ inbox: "Innboks",
+ archive: "Arkiv",
+ archive_all: "Arkiver alt",
+ no_notifications: "Ingen nye varsler"
}
},
header: {
diff --git a/apps/app/src/locales/pt.ts b/apps/app/src/locales/pt.ts
index ffc617ec94..a2bd0dcb51 100644
--- a/apps/app/src/locales/pt.ts
+++ b/apps/app/src/locales/pt.ts
@@ -136,6 +136,12 @@ export default {
uploading_files: "Carregando {target}...",
remove_file: "Remover arquivo"
}
+ },
+ notifications: {
+ inbox: "Caixa de entrada",
+ archive: "Arquivo",
+ archive_all: "Arquivar tudo",
+ no_notifications: "Sem novas notificações"
}
},
header: {
diff --git a/bun.lockb b/bun.lockb
index 17d59db256..338ee6ab69 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/packages/notifications/package.json b/packages/notifications/package.json
new file mode 100644
index 0000000000..909d7d8e3f
--- /dev/null
+++ b/packages/notifications/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "@bubba/notifications",
+ "version": "1.0.0",
+ "private": true,
+ "main": "src/index.ts",
+ "type": "module",
+ "scripts": {
+ "clean": "rm -rf .turbo node_modules",
+ "lint": "biome check .",
+ "format": "biome format --write .",
+ "typecheck": "tsc --noEmit"
+ },
+ "dependencies": {
+ "@novu/node": "^2.0.1",
+ "nanoid": "^5.0.7"
+ },
+ "devDependencies": {
+ "typescript": "^5.6.3"
+ }
+}
diff --git a/packages/notifications/src/index.ts b/packages/notifications/src/index.ts
new file mode 100644
index 0000000000..5a54b3c5c5
--- /dev/null
+++ b/packages/notifications/src/index.ts
@@ -0,0 +1,113 @@
+import { Novu } from "@novu/node";
+import ky from "ky";
+import { nanoid } from "nanoid";
+
+const novu = new Novu(process.env.NOVU_API_KEY!);
+const novu_api = "https://api.novu.co/v1";
+
+export enum TriggerEvents {
+ TaskReminderInApp = "task-reminder-inapp",
+}
+
+export enum NotificationTypes {
+ Task = "task",
+}
+
+type TriggerUser = {
+ subscriberId: string;
+ email: string;
+ fullName: string;
+ image: string;
+ organizationId: string;
+}
+
+type TriggerPayload = {
+ name: TriggerEvents;
+ payload: any;
+ user: TriggerUser;
+ replyTo?: string;
+ tenant?: string; // organization_id + user_id
+}
+
+type GetSubscriberPreferencesParams = {
+ organizationId: string;
+ subscriberId: string;
+}
+
+type UpdateSubscriberPreferencesParams = {
+ subscriberId: string;
+ organizationId: string;
+ templateId: string;
+ type: string;
+ enabled: boolean;
+}
+
+export async function trigger(data: TriggerPayload) {
+ try {
+ const subscriberId = `${data.user.organizationId}_${data.user.subscriberId}`;
+
+ await novu.trigger(data.name, {
+ to: {
+ ...data.user,
+ subscriberId
+ },
+ payload: data.payload,
+ tenant: data.tenant,
+ overrides: {
+ email: {
+ replyTo: data.replyTo,
+ headers: {
+ "X-Entity-Ref-ID": nanoid(),
+ }
+ }
+ }
+ });
+ } catch (error: any) {
+ console.error('Novu trigger error:', {
+ event: data.name,
+ error: error.response?.data || error.message,
+ status: error.response?.status
+ });
+
+ throw error;
+ }
+}
+
+export async function getSubscriberPreferences({ organizationId, subscriberId }: GetSubscriberPreferencesParams) {
+ try {
+ const response = await ky.get(`${novu_api}/subscribers/${organizationId}_${subscriberId}/preferences?includeInactiveChannels=false`, {
+ method: "GET",
+ headers: {
+ Authorization: `ApiKey ${process.env.NOVU_API_KEY!}`,
+ },
+ })
+
+ return response.json();
+ } catch (error) {
+ console.log(error);
+ return null;
+ }
+}
+
+export async function updateSubscriberPreferences({ subscriberId, organizationId, templateId, type, enabled }: UpdateSubscriberPreferencesParams) {
+ try {
+ const response = await ky.patch(`${novu_api}/subscribers/${organizationId}_${subscriberId}/preferences/${templateId}`, {
+ method: "PATCH",
+ headers: {
+ Authorization: `ApiKey ${process.env.NOVU_API_KEY!}`,
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ channel: {
+ type,
+ enabled,
+ },
+ }),
+ })
+
+ return response.json();
+ } catch (error) {
+ console.log(error);
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/packages/notifications/tsconfig.json b/packages/notifications/tsconfig.json
new file mode 100644
index 0000000000..3a0a99d5c6
--- /dev/null
+++ b/packages/notifications/tsconfig.json
@@ -0,0 +1,5 @@
+{
+ "extends": "@bubba/tsconfig/base.json",
+ "include": ["src"],
+ "exclude": ["node_modules"]
+}
diff --git a/turbo.json b/turbo.json
index b22e7c5c43..8c0c5b8ba8 100644
--- a/turbo.json
+++ b/turbo.json
@@ -31,7 +31,8 @@
"VERCEL_AUTH_TOKEN",
"VERCEL_TEAM_ID",
"VERCEL_PROJECT_ID",
- "NEXT_PUBLIC_VERCEL_URL"
+ "NEXT_PUBLIC_VERCEL_URL",
+ "NOVU_API_KEY"
],
"inputs": [
"$TURBO_DEFAULT$",
diff --git a/yarn.lock b/yarn.lock
index 4b9479bf64..d92df5a4c4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1,6 +1,6 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
-# bun ./bun.lockb --hash: E61F2EF946E5A25E-7e221dd7b0c731c7-903B7615989286AD-79b4c36c31dd44c7
+# bun ./bun.lockb --hash: E3588BF47FA0E20B-abcd9cbbd126aa0d-23D6C38DF3A8DD19-ad81e27570f355aa
"@ai-sdk/anthropic@^1.1.6":
@@ -316,7 +316,7 @@
dependencies:
"@babel/types" "^7.26.5"
-"@babel/runtime@^7.13.10", "@babel/runtime@^7.20.13", "@babel/runtime@^7.26.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
+"@babel/runtime@^7.13.10", "@babel/runtime@^7.15.4", "@babel/runtime@^7.20.13", "@babel/runtime@^7.26.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
version "7.26.0"
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz"
integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==
@@ -479,6 +479,15 @@
"@upstash/redis" "^1.34.2"
server-only "^0.0.1"
+"@bubba/notifications@packages/notifications", "@bubba/notifications@workspace:*":
+ version "workspace:packages/notifications"
+ resolved "workspace:packages/notifications"
+ devDependencies:
+ typescript "^5.6.3"
+ dependencies:
+ "@novu/node" "^2.0.1"
+ nanoid "^5.0.7"
+
"@bubba/tsconfig@packages/tsconfig", "@bubba/tsconfig@workspace:*":
version "workspace:packages/tsconfig"
resolved "workspace:packages/tsconfig"
@@ -832,7 +841,7 @@
dependencies:
"@floating-ui/utils" "^0.2.9"
-"@floating-ui/dom@^1.0.0":
+"@floating-ui/dom@^1.0.0", "@floating-ui/dom@^1.5", "@floating-ui/dom@^1.6.7":
version "1.6.13"
resolved "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.13.tgz"
integrity sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==
@@ -1153,6 +1162,59 @@
jju "^1.4.0"
js-yaml "^4.1.0"
+"@motionone/animation@^10.18.0":
+ version "10.18.0"
+ resolved "https://registry.npmjs.org/@motionone/animation/-/animation-10.18.0.tgz"
+ integrity sha512-9z2p5GFGCm0gBsZbi8rVMOAJCtw1WqBTIPw3ozk06gDvZInBPIsQcHgYogEJ4yuHJ+akuW8g1SEIOpTOvYs8hw==
+ dependencies:
+ "@motionone/easing" "^10.18.0"
+ "@motionone/types" "^10.17.1"
+ "@motionone/utils" "^10.18.0"
+ tslib "^2.3.1"
+
+"@motionone/dom@^10.17.0":
+ version "10.18.0"
+ resolved "https://registry.npmjs.org/@motionone/dom/-/dom-10.18.0.tgz"
+ integrity sha512-bKLP7E0eyO4B2UaHBBN55tnppwRnaE3KFfh3Ps9HhnAkar3Cb69kUCJY9as8LrccVYKgHA+JY5dOQqJLOPhF5A==
+ dependencies:
+ "@motionone/animation" "^10.18.0"
+ "@motionone/generators" "^10.18.0"
+ "@motionone/types" "^10.17.1"
+ "@motionone/utils" "^10.18.0"
+ hey-listen "^1.0.8"
+ tslib "^2.3.1"
+
+"@motionone/easing@^10.18.0":
+ version "10.18.0"
+ resolved "https://registry.npmjs.org/@motionone/easing/-/easing-10.18.0.tgz"
+ integrity sha512-VcjByo7XpdLS4o9T8t99JtgxkdMcNWD3yHU/n6CLEz3bkmKDRZyYQ/wmSf6daum8ZXqfUAgFeCZSpJZIMxaCzg==
+ dependencies:
+ "@motionone/utils" "^10.18.0"
+ tslib "^2.3.1"
+
+"@motionone/generators@^10.18.0":
+ version "10.18.0"
+ resolved "https://registry.npmjs.org/@motionone/generators/-/generators-10.18.0.tgz"
+ integrity sha512-+qfkC2DtkDj4tHPu+AFKVfR/C30O1vYdvsGYaR13W/1cczPrrcjdvYCj0VLFuRMN+lP1xvpNZHCRNM4fBzn1jg==
+ dependencies:
+ "@motionone/types" "^10.17.1"
+ "@motionone/utils" "^10.18.0"
+ tslib "^2.3.1"
+
+"@motionone/types@^10.17.1":
+ version "10.17.1"
+ resolved "https://registry.npmjs.org/@motionone/types/-/types-10.17.1.tgz"
+ integrity sha512-KaC4kgiODDz8hswCrS0btrVrzyU2CSQKO7Ps90ibBVSQmjkrt2teqta6/sOG59v7+dPnKMAg13jyqtMKV2yJ7A==
+
+"@motionone/utils@^10.17.0", "@motionone/utils@^10.18.0":
+ version "10.18.0"
+ resolved "https://registry.npmjs.org/@motionone/utils/-/utils-10.18.0.tgz"
+ integrity sha512-3XVF7sgyTSI2KWvTf6uLlBJ5iAgRgmvp3bpuOiQJvInd4nZ19ET8lX5unn30SlmRH7hXbBbH+Gxd0m0klJ3Xtw==
+ dependencies:
+ "@motionone/types" "^10.17.1"
+ hey-listen "^1.0.8"
+ tslib "^2.3.1"
+
"@mui/core-downloads-tracker@^6.4.0":
version "6.4.0"
resolved "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.4.0.tgz"
@@ -1434,6 +1496,34 @@
socket.io-client "4.7.2"
"@tanstack/query-core" "^4.15.1"
+"@novu/js@2.6.5":
+ version "2.6.5"
+ resolved "https://registry.npmjs.org/@novu/js/-/js-2.6.5.tgz"
+ integrity sha512-lh9InJdzyU+nCX9c0P00iHR4Q/R85KhmOdBSW/JLkKdH8755Kc3KO8c9cpvOhGUYhUsVuJcok8wdzj0s/09rMw==
+ dependencies:
+ "@floating-ui/dom" "^1.6.7"
+ class-variance-authority "^0.7.0"
+ clsx "^2.1.1"
+ mitt "^3.0.1"
+ socket.io-client "4.7.2"
+ solid-floating-ui "^0.3.1"
+ solid-js "^1.8.11"
+ solid-motionone "^1.0.1"
+ tailwind-merge "^2.4.0"
+
+"@novu/node@^2.0.1":
+ version "2.6.5"
+ resolved "https://registry.npmjs.org/@novu/node/-/node-2.6.5.tgz"
+ integrity sha512-5GQI6EkjsLNbzUOXIRGbeFNsY1+bzI8sVhoeBCJfnJ9r/elFNRSMYsgVp5dCXtzLBrp7cjMfYNdLFhp1uUNaig==
+ dependencies:
+ axios "^1.6.8"
+ axios-retry "^3.8.0"
+ handlebars "^4.7.7"
+ lodash.get "^4.4.2"
+ lodash.merge "^4.6.2"
+ uuid "^9.0.1"
+ "@novu/shared" "2.6.5"
+
"@novu/ntfr-client@^0.0.4":
version "0.0.4"
resolved "https://registry.npmjs.org/@novu/ntfr-client/-/ntfr-client-0.0.4.tgz"
@@ -1446,11 +1536,23 @@
partysocket "^0.0.17"
proxy-agent "^6.3.0"
+"@novu/react@^2.6.5":
+ version "2.6.5"
+ resolved "https://registry.npmjs.org/@novu/react/-/react-2.6.5.tgz"
+ integrity sha512-LJNeUnEAV6morGvVjv1iaQIov+Q32irESfBmHHI1SjDbVOHD+CPHCkZZ9R3Yb/9IRIUA6PTGb8vWOs2oPaHKSQ==
+ dependencies:
+ "@novu/js" "2.6.5"
+
"@novu/shared@2.1.5":
version "2.1.5"
resolved "https://registry.npmjs.org/@novu/shared/-/shared-2.1.5.tgz"
integrity sha512-bAnZkvljegpf2GdjeYS9lbNp49K9a72OKfDXfYt3tSYB5DaTxj7RdGRaYW1IXDI7UTNEEg7G2XcbC3F7TadrmA==
+"@novu/shared@2.6.5":
+ version "2.6.5"
+ resolved "https://registry.npmjs.org/@novu/shared/-/shared-2.6.5.tgz"
+ integrity sha512-nKSuZ6oIBGezvEP7ICsBT1jtwzL/Y1mzZxpYjmzLiZUXVV35GGk83NqNwjImNjDYAz1c4wVpDb8uV+nMy4e0Tw==
+
"@one-ini/wasm@0.1.1":
version "0.1.1"
resolved "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz"
@@ -2912,6 +3014,30 @@
resolved "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz"
integrity sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==
+"@solid-primitives/props@^3.1.11":
+ version "3.2.0"
+ resolved "https://registry.npmjs.org/@solid-primitives/props/-/props-3.2.0.tgz"
+ integrity sha512-vEg5yERdXftJz2+A6B0IMYTrPL9SE2DPmpURV/nZyqQ+PXziF02V4b4SDr6JX3jNJxBlY6c17LqwYEw+bIfGRg==
+ dependencies:
+ "@solid-primitives/utils" "^6.3.0"
+
+"@solid-primitives/refs@^1.0.8":
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/@solid-primitives/refs/-/refs-1.1.0.tgz"
+ integrity sha512-QJ3bTSQOlPdHBP2m6llrT13FvVzAwZfx41lTN8lQrRwwcZoWb7kfCAjhaohPnwkAsQ6nJpLjtGfT5GOyuCA4tA==
+ dependencies:
+ "@solid-primitives/utils" "^6.3.0"
+
+"@solid-primitives/transition-group@^1.0.5":
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/@solid-primitives/transition-group/-/transition-group-1.1.0.tgz"
+ integrity sha512-pL1sEPCHuC4V+Yh+SQsKSPuGDYrZbLJYSkk3AB4TZrWhptEJUS0IHoi7BAynYcMiULbvMMVKFbeFHqINZq0+ig==
+
+"@solid-primitives/utils@^6.3.0":
+ version "6.3.0"
+ resolved "https://registry.npmjs.org/@solid-primitives/utils/-/utils-6.3.0.tgz"
+ integrity sha512-e7hTlJ1Ywh2+g/Qug+n4L1mpfxsikoIS4/sHE2EK9WatQt8UJqop/vE6bsLnXlU1xuhb/jo94Ah5Y27rd4wP7A==
+
"@standard-schema/spec@1.0.0-beta.3":
version "1.0.0-beta.3"
resolved "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0-beta.3.tgz"
@@ -4505,6 +4631,14 @@ axios@^1.6.8, axios@^1.7.4, axios@^1.7.8, axios@^1.7.9:
proxy-from-env "^1.1.0"
follow-redirects "^1.15.6"
+axios-retry@^3.8.0:
+ version "3.9.1"
+ resolved "https://registry.npmjs.org/axios-retry/-/axios-retry-3.9.1.tgz"
+ integrity sha512-8PJDLJv7qTTMMwdnbMvrLYuvB47M81wRtxQmEdV5w4rgbTXTt+vtPkXwajOfOdSyv/wZICJOC+/UhXH4aQ/R+w==
+ dependencies:
+ "@babel/runtime" "^7.15.4"
+ is-retry-allowed "^2.2.0"
+
axobject-query@^4.1.0:
version "4.1.0"
resolved "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz"
@@ -4977,6 +5111,7 @@ commander@11.1.0:
resolved "workspace:apps/app"
devDependencies:
"@bubba/db" "workspace:*"
+ "@bubba/notifications" "workspace:*"
"@trigger.dev/build" "3.3.13"
"@types/node" "^22.13.0"
"@types/react" "^19.0.8"
@@ -4994,6 +5129,7 @@ commander@11.1.0:
"@nangohq/frontend" "^0.48.4"
"@nangohq/node" "^0.48.4"
"@novu/headless" "^2.0.4"
+ "@novu/react" "^2.6.5"
"@prisma/instrumentation" "^6.3.0"
"@tanstack/react-query" "^5.66.0"
"@tanstack/react-table" "^8.20.6"
@@ -5232,7 +5368,7 @@ cssstyle@^4.2.1:
"@asamuzakjp/css-color" "^2.8.2"
rrweb-cssom "^0.8.0"
-csstype@^3.0.2, csstype@^3.1.3:
+csstype@^3.0.2, csstype@^3.1.0, csstype@^3.1.3:
version "3.1.3"
resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz"
integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
@@ -6636,6 +6772,18 @@ gray-matter@^4.0.3:
section-matter "^1.0.0"
strip-bom-string "^1.0.0"
+handlebars@^4.7.7:
+ version "4.7.8"
+ resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz"
+ integrity sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==
+ dependencies:
+ minimist "^1.2.5"
+ neo-async "^2.6.2"
+ source-map "^0.6.1"
+ wordwrap "^1.0.0"
+ optionalDependencies:
+ uglify-js "^3.1.4"
+
har-schema@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz"
@@ -6725,6 +6873,11 @@ hast-util-whitespace@^3.0.0:
dependencies:
"@types/hast" "^3.0.0"
+hey-listen@^1.0.8:
+ version "1.0.8"
+ resolved "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz"
+ integrity sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==
+
highlight.js@^11, highlight.js@^11.11.1, highlight.js@~11.11.0:
version "11.11.1"
resolved "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz"
@@ -7180,6 +7333,11 @@ is-regex@^1.2.1:
has-tostringtag "^1.0.2"
hasown "^2.0.2"
+is-retry-allowed@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz"
+ integrity sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==
+
is-set@^2.0.2, is-set@^2.0.3:
version "2.0.3"
resolved "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz"
@@ -7651,6 +7809,11 @@ lodash.camelcase@^4.3.0:
resolved "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz"
integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==
+lodash.get@^4.4.2:
+ version "4.4.2"
+ resolved "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz"
+ integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==
+
lodash.includes@^4.3.0:
version "4.3.0"
resolved "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz"
@@ -8354,7 +8517,7 @@ minimatch@^9.0.1, minimatch@^9.0.4:
dependencies:
brace-expansion "^2.0.1"
-minimist@^1.2.0, minimist@^1.2.6:
+minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6:
version "1.2.8"
resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz"
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
@@ -8450,6 +8613,11 @@ nanoid@^3.3.4, nanoid@^3.3.6, nanoid@^3.3.7, nanoid@^3.3.8:
resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz"
integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==
+nanoid@^5.0.7:
+ version "5.0.9"
+ resolved "https://registry.npmjs.org/nanoid/-/nanoid-5.0.9.tgz"
+ integrity sha512-Aooyr6MXU6HpvvWXKoVoXwKMs/KyVakWwg7xQfv5/S/RIgJMy0Ifa45H9qqYy7pTCszrHzP21Uk4PZq2HpEM8Q==
+
negotiator@0.6.3:
version "0.6.3"
resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz"
@@ -8460,6 +8628,11 @@ negotiator@^1.0.0:
resolved "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz"
integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==
+neo-async@^2.6.2:
+ version "2.6.2"
+ resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz"
+ integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
+
netmask@^2.0.2:
version "2.0.2"
resolved "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz"
@@ -9690,7 +9863,7 @@ react@18.2.0, react@18.x, "react@^16.8 || ^17.0 || ^18.0", react@^18.0.0, react@
dependencies:
loose-envify "^1.1.0"
-react@*, react@19.0.0, "react@>= 16.8 || 18.0.0", "react@>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0", "react@>= 18.0.0", "react@>= 18.2.0", react@>=16, react@>=16.6.0, react@>=16.8, "react@>=16.8.0 || ^17.0.0 || ^18", react@>=16.8.1, react@>=18, "react@>=18.2.0 || ^19.0.0-0", "react@^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react@^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc", "react@^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react@^16.8.0 || ^17 || ^18 || ^19", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react@^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react@^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc", "react@^17.0.0 || ^18.0.0 || ^19.0.0", "react@^17.0.2 || ^18.0.0 || ^19.0.0", "react@^18 || ^19", "react@^18 || ^19 || ^19.0.0-rc", "react@^18.0 || ^19.0", "react@^18.0 || ^19.0 || ^19.0.0-rc", "react@^18.2.0 || 19.0.0-rc-66855b96-20241106 || ^19.0.0", "react@^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react@^18.2.0 || ^19.0.0-0", react@^19.0.0:
+react@*, react@19.0.0, "react@>= 16.8 || 18.0.0", "react@>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0", "react@>= 18.0.0", "react@>= 18.2.0", react@>=16, react@>=16.6.0, react@>=16.8, "react@>=16.8.0 || ^17.0.0 || ^18", react@>=16.8.1, react@>=17, react@>=18, "react@>=18.2.0 || ^19.0.0-0", "react@^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react@^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc", "react@^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react@^16.8.0 || ^17 || ^18 || ^19", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react@^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react@^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc", "react@^17.0.0 || ^18.0.0 || ^19.0.0", "react@^17.0.2 || ^18.0.0 || ^19.0.0", "react@^18 || ^19", "react@^18 || ^19 || ^19.0.0-rc", "react@^18.0 || ^19.0", "react@^18.0 || ^19.0 || ^19.0.0-rc", "react@^18.2.0 || 19.0.0-rc-66855b96-20241106 || ^19.0.0", "react@^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react@^18.2.0 || ^19.0.0-0", react@^19.0.0:
version "19.0.0"
resolved "https://registry.npmjs.org/react/-/react-19.0.0.tgz"
integrity sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==
@@ -10362,6 +10535,16 @@ send@0.19.0:
on-finished "2.4.1"
range-parser "~1.2.1"
+seroval@^1.0, seroval@^1.1.0:
+ version "1.2.1"
+ resolved "https://registry.npmjs.org/seroval/-/seroval-1.2.1.tgz"
+ integrity sha512-yBxFFs3zmkvKNmR0pFSU//rIsYjuX418TnlDmc2weaq5XFDqDIV/NOMPBoLrbxjLH42p4UzRuXHryXh9dYcKcw==
+
+seroval-plugins@^1.1.0:
+ version "1.2.1"
+ resolved "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.2.1.tgz"
+ integrity sha512-H5vs53+39+x4Udwp4J5rNZfgFuA+Lt+uU+09w1gYBVWomtAl98B+E9w7yC05Xc81/HgLvJdlyqJbU0fJCKCmdw==
+
serve-static@1.16.2:
version "1.16.2"
resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz"
@@ -10611,12 +10794,38 @@ socks-proxy-agent@^8.0.5:
debug "^4.3.4"
socks "^2.8.3"
+solid-floating-ui@^0.3.1:
+ version "0.3.1"
+ resolved "https://registry.npmjs.org/solid-floating-ui/-/solid-floating-ui-0.3.1.tgz"
+ integrity sha512-o/QmGsWPS2Z3KidAxP0nDvN7alI7Kqy0kU+wd85Fz+au5SYcnYm7I6Fk3M60Za35azsPX0U+5fEtqfOuk6Ao0Q==
+
+solid-js@^1.6.12, solid-js@^1.8, solid-js@^1.8.11:
+ version "1.9.4"
+ resolved "https://registry.npmjs.org/solid-js/-/solid-js-1.9.4.tgz"
+ integrity sha512-ipQl8FJ31bFUoBNScDQTG3BjN6+9Rg+Q+f10bUbnO6EOTTf5NGerJeHc7wyu5I4RMHEl/WwZwUmy/PTRgxxZ8g==
+ dependencies:
+ csstype "^3.1.0"
+ seroval "^1.1.0"
+ seroval-plugins "^1.1.0"
+
+solid-motionone@^1.0.1:
+ version "1.0.3"
+ resolved "https://registry.npmjs.org/solid-motionone/-/solid-motionone-1.0.3.tgz"
+ integrity sha512-C1XGpbKz7klrYwYPI75X0TJdIIJWMslLPUIgnu9a0jXqN6TWA65+EByBkhVarZeBfNjVg3+uOrIRFewqZkjuFA==
+ dependencies:
+ "@motionone/dom" "^10.17.0"
+ "@motionone/utils" "^10.17.0"
+ "@solid-primitives/props" "^3.1.11"
+ "@solid-primitives/refs" "^1.0.8"
+ "@solid-primitives/transition-group" "^1.0.5"
+ csstype "^3.1.3"
+
sonner@^1.7.4:
version "1.7.4"
resolved "https://registry.npmjs.org/sonner/-/sonner-1.7.4.tgz"
integrity sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw==
-source-map@~0.6.1:
+source-map@^0.6.1:
version "0.6.1"
resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
@@ -10941,7 +11150,7 @@ tailwind-merge@2.5.3:
resolved "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.5.3.tgz"
integrity sha512-d9ZolCAIzom1nf/5p4LdD5zvjmgSxY0BGgdSvmXIoMYAiPdAW/dSpP7joCDYFY7r/HkEa2qmPtkgsu0xjQeQtw==
-tailwind-merge@^2.6.0:
+tailwind-merge@^2.4.0, tailwind-merge@^2.6.0:
version "2.6.0"
resolved "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.0.tgz"
integrity sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==
@@ -11193,7 +11402,7 @@ tsconfck@3.1.3:
resolved "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.3.tgz"
integrity sha512-ulNZP1SVpRDesxeMLON/LtWM8HIgAJEIVpVVhBM6gsmvQ8+Rh+ZG7FWGvHh7Ah3pRABwVJWklWCr/BTZSv0xnQ==
-tslib@2, tslib@^2.0.0, tslib@^2.0.1, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.4.1, tslib@^2.7.0, tslib@^2.8.0:
+tslib@2, tslib@^2.0.0, tslib@^2.0.1, tslib@^2.1.0, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.4.1, tslib@^2.7.0, tslib@^2.8.0:
version "2.8.1"
resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz"
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
@@ -11359,6 +11568,11 @@ ufo@^1.5.4:
resolved "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz"
integrity sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==
+uglify-js@^3.1.4:
+ version "3.19.3"
+ resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz"
+ integrity sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==
+
ulid@^2.3.0:
version "2.3.0"
resolved "https://registry.npmjs.org/ulid/-/ulid-2.3.0.tgz"
@@ -11556,7 +11770,7 @@ uuid@^3.3.2:
resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
-uuid@^9.0.0:
+uuid@^9.0.0, uuid@^9.0.1:
version "9.0.1"
resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz"
integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==
@@ -11829,6 +12043,11 @@ wide-align@^1.1.0:
dependencies:
string-width "^1.0.2 || 2 || 3 || 4"
+wordwrap@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz"
+ integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==
+
wordwrapjs@^5.1.0:
version "5.1.0"
resolved "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-5.1.0.tgz"