From 37081cab761a0631370ff015919f72fec251cc93 Mon Sep 17 00:00:00 2001 From: Naomi Carrigan Date: Sat, 5 Jul 2025 19:27:20 -0700 Subject: [PATCH] feat: client and server logic to manage announcements (#3) ### Explanation _No response_ ### Issue _No response_ ### Attestations - [x] I have read and agree to the [Code of Conduct](https://docs.nhcarrigan.com/community/coc/) - [x] I have read and agree to the [Community Guidelines](https://docs.nhcarrigan.com/community/guide/). - [x] My contribution complies with the [Contributor Covenant](https://docs.nhcarrigan.com/dev/covenant/). ### Dependencies - [x] I have pinned the dependencies to a specific patch version. ### Style - [x] I have run the linter and resolved any errors. - [x] My pull request uses an appropriate title, matching the conventional commit standards. - [x] My scope of feat/fix/chore/etc. correctly matches the nature of changes in my pull request. ### Tests - [ ] My contribution adds new code, and I have added tests to cover it. - [ ] My contribution modifies existing code, and I have updated the tests to reflect these changes. - [ ] All new and existing tests pass locally with my changes. - [ ] Code coverage remains at or above the configured threshold. ### Documentation _No response_ ### Versioning _No response_ Reviewed-on: https://git.nhcarrigan.com/nhcarrigan/hikari/pulls/3 Co-authored-by: Naomi Carrigan Co-committed-by: Naomi Carrigan --- .gitea/workflows/ci.yml | 3 + client/package.json | 1 + client/src/app/announcements.ts | 38 + .../src/app/announcements/announcements.css | 37 + .../src/app/announcements/announcements.html | 20 + client/src/app/announcements/announcements.ts | 39 + client/src/app/app.routes.ts | 2 + client/src/app/home/home.css | 12 +- client/src/app/home/home.html | 10 +- client/src/app/nav/nav.html | 2 + pnpm-lock.yaml | 1490 +++++++++++++++-- server/dev.env | 5 + server/eslint.config.js | 15 +- server/package.json | 7 +- server/prisma/schema.prisma | 19 + server/prod.env | 4 + server/src/cache/blockedIps.ts | 7 + server/src/config/routesWithoutCors.ts | 15 + server/src/db/database.ts | 24 + server/src/hooks/cors.ts | 42 + server/src/hooks/ips.ts | 36 + server/src/index.ts | 28 +- server/src/modules/announceOnDiscord.ts | 65 + server/src/modules/announceOnForum.ts | 40 + server/src/modules/getIpFromRequest.ts | 25 + server/src/routes/announcement.ts | 110 ++ server/src/routes/base.ts | 23 + 27 files changed, 2012 insertions(+), 107 deletions(-) create mode 100644 client/src/app/announcements.ts create mode 100644 client/src/app/announcements/announcements.css create mode 100644 client/src/app/announcements/announcements.html create mode 100644 client/src/app/announcements/announcements.ts create mode 100644 server/dev.env create mode 100644 server/prisma/schema.prisma create mode 100644 server/src/cache/blockedIps.ts create mode 100644 server/src/config/routesWithoutCors.ts create mode 100644 server/src/db/database.ts create mode 100644 server/src/hooks/cors.ts create mode 100644 server/src/hooks/ips.ts create mode 100644 server/src/modules/announceOnDiscord.ts create mode 100644 server/src/modules/announceOnForum.ts create mode 100644 server/src/modules/getIpFromRequest.ts create mode 100644 server/src/routes/announcement.ts create mode 100644 server/src/routes/base.ts diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 7d965a9..780d023 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -28,6 +28,9 @@ jobs: - name: Install Dependencies run: pnpm install + - name: Generate Database Schema + run: cd server && pnpm prisma generate + - name: Lint Source Files run: pnpm run lint diff --git a/client/package.json b/client/package.json index 73d8e53..2652659 100644 --- a/client/package.json +++ b/client/package.json @@ -28,6 +28,7 @@ "@angular/forms": "20.0.6", "@angular/platform-browser": "20.0.6", "@angular/router": "20.0.6", + "ngx-markdown": "20.0.0", "rxjs": "7.8.2", "tslib": "2.8.1", "zone.js": "0.15.1" diff --git a/client/src/app/announcements.ts b/client/src/app/announcements.ts new file mode 100644 index 0000000..35e7636 --- /dev/null +++ b/client/src/app/announcements.ts @@ -0,0 +1,38 @@ +/** + * @copyright nhcarrigan + * @license Naomi's Public License + * @author Naomi Carrigan + */ +import { Injectable } from "@angular/core"; + +@Injectable({ + providedIn: "root", +}) +export class AnnouncementsService { + public constructor() {} + // eslint-disable-next-line @typescript-eslint/class-methods-use-this -- Getter for static URL. + private get url(): string { + return "http://localhost:20000/announcements"; + } + + public async getAnnouncements(): Promise< + Array<{ + title: string; + content: string; + createdAt: string; + type: "products" | "community"; + }> + > { + const response = await fetch(this.url); + if (!response.ok) { + return []; + } + + return (await response.json()) as Array<{ + title: string; + content: string; + createdAt: string; + type: "products" | "community"; + }>; + } +} diff --git a/client/src/app/announcements/announcements.css b/client/src/app/announcements/announcements.css new file mode 100644 index 0000000..fafbb3e --- /dev/null +++ b/client/src/app/announcements/announcements.css @@ -0,0 +1,37 @@ +hr { + width: 100%; + border: none; + border-top: 1px solid var(--foreground); + margin: 0; +} + +:host ::ng-deep ul{ + list-style-type: disc; + list-style-position: inside; +} + +.announcement { + margin: auto; + margin-bottom: 1em; + width: 90%; +} +.tag { + display: inline-block; + padding: 0 0.5em; + border-radius: 50px; + font-size: 0.8em; +} + +.products { + background-color: #e0f7fa; + color: #006064; +} + +.community { + background-color: #e8f5e9; + color: #1b5e20; +} + +.date { + font-style: italic; +} diff --git a/client/src/app/announcements/announcements.html b/client/src/app/announcements/announcements.html new file mode 100644 index 0000000..1e8e3e5 --- /dev/null +++ b/client/src/app/announcements/announcements.html @@ -0,0 +1,20 @@ +

Announcements

+

Here are the most recent updates for our products and communities.

+

+ If you want to see the full history, check out our + chat server or our + forum. +

+
+
+

{{ announcement.title }}

+

+ {{announcement.type}} + {{ announcement.createdAt | date: "mediumDate" }} +

+ +

Type: {{ announcement.type }}

+
+
+

There are no announcements at this time.

+
diff --git a/client/src/app/announcements/announcements.ts b/client/src/app/announcements/announcements.ts new file mode 100644 index 0000000..4afb35c --- /dev/null +++ b/client/src/app/announcements/announcements.ts @@ -0,0 +1,39 @@ +/** + * @copyright nhcarrigan + * @license Naomi's Public License + * @author Naomi Carrigan + */ +import { CommonModule, DatePipe } from "@angular/common"; +import { Component, SecurityContext } from "@angular/core"; +import { MarkdownComponent, provideMarkdown } from "ngx-markdown"; +import { AnnouncementsService } from "../announcements.js"; + +@Component({ + imports: [ CommonModule, DatePipe, MarkdownComponent ], + providers: [ provideMarkdown({ sanitize: SecurityContext.HTML }) ], + selector: "app-announcements", + styleUrl: "./announcements.css", + templateUrl: "./announcements.html", +}) +export class Announcements { + public announcements: Array<{ + title: string; + content: string; + createdAt: string; + type: "products" | "community"; + }> = []; + public constructor( + private readonly announcementsService: AnnouncementsService, + ) { + void this.loadAnnouncements(); + } + + private async loadAnnouncements(): Promise { + const announcements = await this.announcementsService.getAnnouncements(); + this.announcements = announcements.sort((a, b) => { + return b.createdAt > a.createdAt + ? 1 + : -1; + }); + } +} diff --git a/client/src/app/app.routes.ts b/client/src/app/app.routes.ts index fd3e26b..4a58aa6 100644 --- a/client/src/app/app.routes.ts +++ b/client/src/app/app.routes.ts @@ -5,6 +5,7 @@ */ import { Routes } from "@angular/router"; +import { Announcements } from "./announcements/announcements.js"; import { Home } from "./home/home.js"; import { Products } from "./products/products.js"; import { Soon } from "./soon/soon.js"; @@ -12,5 +13,6 @@ import { Soon } from "./soon/soon.js"; export const routes: Routes = [ { component: Home, path: "", pathMatch: "full" }, { component: Products, path: "products" }, + { component: Announcements, path: "announcements" }, { component: Soon, path: "**" }, ]; diff --git a/client/src/app/home/home.css b/client/src/app/home/home.css index f54fb81..4fc11aa 100644 --- a/client/src/app/home/home.css +++ b/client/src/app/home/home.css @@ -4,6 +4,11 @@ ul { margin: 0; } +::ng-deep main{ + overflow: hidden !important; + max-width: 100%; +} + #one { transform: translateY(-200vh); animation: slide-down 2s forwards; @@ -35,9 +40,14 @@ ul { animation: slide-right 2s forwards 10s; } +#seven { + transform: translateX(-200vw); + animation: slide-left 2s forwards 12s; +} + #fade { opacity: 0; - animation: fade-in 2s forwards 12s; + animation: fade-in 2s forwards 14s; display: flex; flex-direction: row; justify-content: space-evenly; diff --git a/client/src/app/home/home.html b/client/src/app/home/home.html index 28b1191..d458a8f 100644 --- a/client/src/app/home/home.html +++ b/client/src/app/home/home.html @@ -7,12 +7,14 @@

How may I help you today?

I can assist you with:

    -
  • Finding a product to suit your needs
  • -
  • Manage your account, subscriptions, and licenses
  • -
  • Modifying settings for individual products
  • -
  • Answering your specific questions with a chat assistant
  • +
  • Checking the latest updates.
  • +
  • Finding a product to suit your needs
  • +
  • Manage your account, subscriptions, and licenses
  • +
  • Modifying settings for individual products
  • +
  • Answering your specific questions with a chat assistant
+ View Announcements Browse Products Manage Account Modify Settings diff --git a/client/src/app/nav/nav.html b/client/src/app/nav/nav.html index a602807..d2a515f 100644 --- a/client/src/app/nav/nav.html +++ b/client/src/app/nav/nav.html @@ -5,6 +5,8 @@ >
+ Announcements +
Products
Account diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d2d19d4..c0e6402 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,13 +10,13 @@ importers: devDependencies: '@nhcarrigan/eslint-config': specifier: 5.2.0 - version: 5.2.0(@typescript-eslint/utils@8.35.1(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.30.1(jiti@1.21.7))(playwright@1.53.2)(react@19.1.0)(typescript@5.8.3)(vitest@3.2.4(@types/node@24.0.10)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)) + version: 5.2.0(@typescript-eslint/utils@8.35.1(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3))(eslint@9.30.1(jiti@2.4.2))(playwright@1.53.2)(react@19.1.0)(typescript@5.8.3)(vitest@3.2.4(@types/node@24.0.10)(jiti@2.4.2)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(tsx@4.20.3)) '@nhcarrigan/typescript-config': specifier: 4.0.0 version: 4.0.0(typescript@5.8.3) eslint: specifier: 9.30.1 - version: 9.30.1(jiti@1.21.7) + version: 9.30.1(jiti@2.4.2) turbo: specifier: 2.5.4 version: 2.5.4 @@ -44,6 +44,9 @@ importers: '@angular/router': specifier: 20.0.6 version: 20.0.6(@angular/common@20.0.6(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.0.6(@angular/common@20.0.6(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2) + ngx-markdown: + specifier: 20.0.0 + version: 20.0.0(@angular/common@20.0.6(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.0.6(@angular/common@20.0.6(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1)))(marked@15.0.12)(rxjs@7.8.2)(zone.js@0.15.1) rxjs: specifier: 7.8.2 version: 7.8.2 @@ -56,7 +59,7 @@ importers: devDependencies: '@angular/build': specifier: 20.0.5 - version: 20.0.5(@angular/compiler-cli@20.0.6(@angular/compiler@20.0.6)(typescript@5.8.3))(@angular/compiler@20.0.6)(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.0.6(@angular/common@20.0.6(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.0.10)(chokidar@4.0.3)(jiti@1.21.7)(karma@6.4.4)(less@4.3.0)(postcss@8.5.6)(terser@5.39.1)(tslib@2.8.1)(typescript@5.8.3)(vitest@3.2.4(@types/node@24.0.10)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)) + version: 20.0.5(@angular/compiler-cli@20.0.6(@angular/compiler@20.0.6)(typescript@5.8.3))(@angular/compiler@20.0.6)(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.0.6(@angular/common@20.0.6(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.0.10)(chokidar@4.0.3)(jiti@2.4.2)(karma@6.4.4)(less@4.3.0)(postcss@8.5.6)(terser@5.39.1)(tslib@2.8.1)(tsx@4.20.3)(typescript@5.8.3)(vitest@3.2.4(@types/node@24.0.10)(jiti@2.4.2)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(tsx@4.20.3)) '@angular/cli': specifier: 20.0.5 version: 20.0.5(@types/node@24.0.10)(chokidar@4.0.3) @@ -90,9 +93,15 @@ importers: server: dependencies: + '@fastify/cors': + specifier: 11.0.1 + version: 11.0.1 '@nhcarrigan/logger': specifier: 1.0.0 version: 1.0.0 + '@prisma/client': + specifier: 6.11.1 + version: 6.11.1(prisma@6.11.1(typescript@5.8.3))(typescript@5.8.3) fastify: specifier: 5.4.0 version: 5.4.0 @@ -100,6 +109,12 @@ importers: '@types/node': specifier: 24.0.10 version: 24.0.10 + prisma: + specifier: 6.11.1 + version: 6.11.1(typescript@5.8.3) + tsx: + specifier: 4.20.3 + version: 4.20.3 packages: @@ -239,6 +254,12 @@ packages: '@angular/platform-browser': 20.0.6 rxjs: ^6.5.3 || ^7.4.0 + '@antfu/install-pkg@1.1.0': + resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} + + '@antfu/utils@8.1.1': + resolution: {integrity: sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ==} + '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} @@ -322,6 +343,24 @@ packages: resolution: {integrity: sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg==} engines: {node: '>=6.9.0'} + '@braintree/sanitize-url@7.1.1': + resolution: {integrity: sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==} + + '@chevrotain/cst-dts-gen@11.0.3': + resolution: {integrity: sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==} + + '@chevrotain/gast@11.0.3': + resolution: {integrity: sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==} + + '@chevrotain/regexp-to-ast@11.0.3': + resolution: {integrity: sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==} + + '@chevrotain/types@11.0.3': + resolution: {integrity: sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==} + + '@chevrotain/utils@11.0.3': + resolution: {integrity: sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==} + '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} @@ -548,6 +587,9 @@ packages: '@fastify/ajv-compiler@4.0.2': resolution: {integrity: sha512-Rkiu/8wIjpsf46Rr+Fitd3HRP+VsxUFDDeag0hs9L0ksfnwx2g7SPQQTFL0E8Qv+rfXzQOxBJnjUB9ITUDjfWQ==} + '@fastify/cors@11.0.1': + resolution: {integrity: sha512-dmZaE7M1f4SM8ZZuk5RhSsDJ+ezTgI7v3HHRj8Ow9CneczsPLZV6+2j2uwdaSLn8zhTv6QV0F4ZRcqdalGx1pQ==} + '@fastify/error@4.2.0': resolution: {integrity: sha512-RSo3sVDXfHskiBZKBPRgnQTtIqpi/7zhJOEmAxCiBcM7d0uwdGdxLlsCaLzGs8v8NnxIRlfG0N51p5yFaOentQ==} @@ -583,6 +625,12 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + + '@iconify/utils@2.3.0': + resolution: {integrity: sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==} + '@inquirer/checkbox@4.1.9': resolution: {integrity: sha512-DBJBkzI5Wx4jFaYm221LHvAhpKYkhVS0k9plqHwaHhofGNxvYB7J3Bz8w+bFJ05zaMb0sZNHo4KdmENQFlNTuQ==} engines: {node: '>=18'} @@ -786,6 +834,9 @@ packages: cpu: [x64] os: [win32] + '@mermaid-js/parser@0.6.0': + resolution: {integrity: sha512-7DNESgpyZ5WG1SIkrYafVBhWmImtmQuoxOO1lawI3gQYWxBX3v1FW3IyuuRfKJAO06XrZR71W0Kif5VEGGd4VA==} + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': resolution: {integrity: sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==} cpu: [arm64] @@ -1074,6 +1125,36 @@ packages: resolution: {integrity: sha512-fdDH1LSGfZdTH2sxdpVMw31BanV28K/Gry0cVFxaNP77neJSkd82mM8ErPNYs9e+0O7SdHBLTDzDgwUuy18RnQ==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@prisma/client@6.11.1': + resolution: {integrity: sha512-5CLFh8QP6KxRm83pJ84jaVCeSVPQr8k0L2SEtOJHwdkS57/VQDcI/wQpGmdyOZi+D9gdNabdo8tj1Uk+w+upsQ==} + engines: {node: '>=18.18'} + peerDependencies: + prisma: '*' + typescript: '>=5.1.0' + peerDependenciesMeta: + prisma: + optional: true + typescript: + optional: true + + '@prisma/config@6.11.1': + resolution: {integrity: sha512-z6rCTQN741wxDq82cpdzx2uVykpnQIXalLhrWQSR0jlBVOxCIkz3HZnd8ern3uYTcWKfB3IpVAF7K2FU8t/8AQ==} + + '@prisma/debug@6.11.1': + resolution: {integrity: sha512-lWRb/YSWu8l4Yum1UXfGLtqFzZkVS2ygkWYpgkbgMHn9XJlMITIgeMvJyX5GepChzhmxuSuiq/MY/kGFweOpGw==} + + '@prisma/engines-version@6.11.1-1.f40f79ec31188888a2e33acda0ecc8fd10a853a9': + resolution: {integrity: sha512-swFJTOOg4tHyOM1zB/pHb3MeH0i6t7jFKn5l+ZsB23d9AQACuIRo9MouvuKGvnDogzkcjbWnXi/NvOZ0+n5Jfw==} + + '@prisma/engines@6.11.1': + resolution: {integrity: sha512-6eKEcV6V8W2eZAUwX2xTktxqPM4vnx3sxz3SDtpZwjHKpC6lhOtc4vtAtFUuf5+eEqBk+dbJ9Dcaj6uQU+FNNg==} + + '@prisma/fetch-engine@6.11.1': + resolution: {integrity: sha512-NBYzmkXTkj9+LxNPRSndaAeALOL1Gr3tjvgRYNqruIPlZ6/ixLeuE/5boYOewant58tnaYFZ5Ne0jFBPfGXHpQ==} + + '@prisma/get-platform@6.11.1': + resolution: {integrity: sha512-b2Z8oV2gwvdCkFemBTFd0x4lsL4O2jLSx8lB7D+XqoFALOQZPa7eAPE1NU0Mj1V8gPHRxIsHnyUNtw2i92psUw==} + '@rollup/rollup-android-arm-eabi@4.40.2': resolution: {integrity: sha512-JkdNEq+DFxZfUwxvB58tHMHBHVgX23ew41g1OQinthJ+ryhdRk67O31S7sYw8u2lTjHUPFxwar07BBt1KHp/hg==} cpu: [arm] @@ -1328,6 +1409,99 @@ packages: '@types/cors@2.8.19': resolution: {integrity: sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==} + '@types/d3-array@3.2.1': + resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==} + + '@types/d3-axis@3.0.6': + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + + '@types/d3-brush@3.0.6': + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + + '@types/d3-chord@3.0.6': + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-contour@3.0.6': + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + + '@types/d3-delaunay@6.0.4': + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + + '@types/d3-dispatch@3.0.6': + resolution: {integrity: sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-dsv@3.0.7': + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + + '@types/d3-fetch@3.0.7': + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + + '@types/d3-force@3.0.10': + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + + '@types/d3-format@3.0.4': + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + + '@types/d3-geo@3.1.0': + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + + '@types/d3-hierarchy@3.1.7': + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-path@3.1.1': + resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + + '@types/d3-polygon@3.0.2': + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + + '@types/d3-quadtree@3.0.6': + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + + '@types/d3-random@3.0.3': + resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} + + '@types/d3-scale-chromatic@3.1.0': + resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} + + '@types/d3-scale@4.0.9': + resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + + '@types/d3-shape@3.1.7': + resolution: {integrity: sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==} + + '@types/d3-time-format@4.0.3': + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + + '@types/d3-time@3.0.4': + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + + '@types/d3@7.4.3': + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} @@ -1337,6 +1511,9 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/geojson@7946.0.16': + resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} + '@types/jasmine@5.1.8': resolution: {integrity: sha512-u7/CnvRdh6AaaIzYjCgUuVbREFgulhX05Qtf6ZtW+aOcjCKKVvKgpkPYJBFTZSHtFBYimzU4zP0V2vrEsq9Wcg==} @@ -1352,6 +1529,9 @@ packages: '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@typescript-eslint/eslint-plugin@8.19.0': resolution: {integrity: sha512-NggSaEZCdSrFddbctrVjkVZvFC6KGfKfNK0CU7mNK/iKHGKbzT4Wmgm08dKpcZECBu9f5FypndoMyRHkdqfT1Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1742,6 +1922,14 @@ packages: resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} engines: {node: '>= 16'} + chevrotain-allstar@0.3.1: + resolution: {integrity: sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==} + peerDependencies: + chevrotain: ^11.0.0 + + chevrotain@11.0.3: + resolution: {integrity: sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==} + chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -1782,6 +1970,9 @@ packages: resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} engines: {node: '>= 12'} + clipboard@2.0.11: + resolution: {integrity: sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==} + cliui@7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} @@ -1806,6 +1997,14 @@ packages: commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + comment-parser@1.4.1: resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} engines: {node: '>= 12.0.0'} @@ -1813,6 +2012,12 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + confbox@0.2.2: + resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} + connect@3.7.0: resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} engines: {node: '>= 0.10.0'} @@ -1845,6 +2050,12 @@ packages: resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} engines: {node: '>= 0.10'} + cose-base@1.0.3: + resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} + + cose-base@2.2.0: + resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -1859,6 +2070,162 @@ packages: custom-event@1.0.1: resolution: {integrity: sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==} + cytoscape-cose-bilkent@4.1.0: + resolution: {integrity: sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape-fcose@2.2.0: + resolution: {integrity: sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape@3.32.0: + resolution: {integrity: sha512-5JHBC9n75kz5851jeklCPmZWcg3hUe6sjqJvyk3+hVqFaKcHwHgxsjeN1yLmggoUc6STbtm9/NQyabQehfjvWQ==} + engines: {node: '>=0.10'} + + d3-array@2.12.1: + resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==} + + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-axis@3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + + d3-brush@3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + + d3-chord@3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-contour@4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + + d3-delaunay@6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-dsv@3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-fetch@3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + + d3-force@3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + + d3-format@3.1.0: + resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} + engines: {node: '>=12'} + + d3-geo@3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + + d3-hierarchy@3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-path@1.0.9: + resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==} + + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-polygon@3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + + d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + + d3-random@3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + + d3-sankey@0.12.3: + resolution: {integrity: sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==} + + d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-shape@1.3.7: + resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==} + + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + d3@7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + + dagre-d3-es@7.0.11: + resolution: {integrity: sha512-tvlJLyQf834SylNKax8Wkzco/1ias1OPw8DcUMDE7oUIoSEW25riQVuiu/0OWEFqT0cxHT3Pa9/D82Jr47IONw==} + data-view-buffer@1.0.2: resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} engines: {node: '>= 0.4'} @@ -1875,6 +2242,9 @@ packages: resolution: {integrity: sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==} engines: {node: '>=4.0'} + dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -1924,6 +2294,12 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + delaunator@5.0.1: + resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} + + delegate@3.2.0: + resolution: {integrity: sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==} + depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -1969,6 +2345,9 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} + dompurify@3.2.6: + resolution: {integrity: sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==} + domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} @@ -1994,6 +2373,9 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + emoji-toolkit@9.0.1: + resolution: {integrity: sha512-sMMNqKNLVHXJfIKoPbrRJwtYuysVNC9GlKetr72zE3SSVbHqoeDLWVrxP0uM0AE0qvdl3hbUk+tJhhwXZrDHaw==} + encodeurl@1.0.2: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} @@ -2228,6 +2610,9 @@ packages: exponential-backoff@3.1.2: resolution: {integrity: sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==} + exsolve@1.0.7: + resolution: {integrity: sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==} + extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} @@ -2264,6 +2649,9 @@ packages: fast-uri@3.0.6: resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} + fastify-plugin@5.0.1: + resolution: {integrity: sha512-HCxs+YnRaWzCl+cWRYFnHmeRFyR5GVnJTAaCJQiYzQSDwK9MgJdyAsuL3nh0EWRCYMgQ5MeziymvmAhUHYHDUQ==} + fastify@5.4.0: resolution: {integrity: sha512-I4dVlUe+WNQAhKSyv15w+dwUh2EPiEl4X2lGYMmNSgF83WzTMAPKGdWEv5tPsCQOb+SOZwz8Vlta2vF+OeDgRw==} @@ -2385,6 +2773,9 @@ packages: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} + get-tsconfig@4.10.1: + resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -2424,6 +2815,9 @@ packages: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} + good-listener@1.2.2: + resolution: {integrity: sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==} + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -2434,6 +2828,9 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + hachure-fill@0.5.2: + resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==} + has-bigints@1.1.0: resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} engines: {node: '>= 0.4'} @@ -2544,6 +2941,13 @@ packages: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} + internmap@1.0.1: + resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==} + + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + ip-address@9.0.5: resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} engines: {node: '>= 12'} @@ -2741,8 +3145,8 @@ packages: jasmine-core@5.8.0: resolution: {integrity: sha512-Q9dqmpUAfptwyueW3+HqBOkSuYd9I/clZSSfN97wXE/Nr2ROFNCwIBEC1F6kb3QXS9Fcz0LjFYSDQT+BiwjuhA==} - jiti@1.21.7: - resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} + jiti@2.4.2: + resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} hasBin: true js-tokens@4.0.0: @@ -2841,9 +3245,29 @@ packages: engines: {node: '>= 10'} hasBin: true + katex@0.16.22: + resolution: {integrity: sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg==} + hasBin: true + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + khroma@2.1.0: + resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==} + + kolorist@1.8.0: + resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} + + langium@3.3.1: + resolution: {integrity: sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==} + engines: {node: '>=16.0.0'} + + layout-base@1.0.2: + resolution: {integrity: sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==} + + layout-base@2.0.1: + resolution: {integrity: sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==} + less@4.3.0: resolution: {integrity: sha512-X9RyH9fvemArzfdP8Pi3irr7lor2Ok4rOttDXBhlwDg+wKQsXOXgHWduAJE1EsF7JJx0w0bcO6BC6tCKKYnXKA==} engines: {node: '>=14'} @@ -2867,6 +3291,10 @@ packages: resolution: {integrity: sha512-MgJocUI6QEiSXQBFWLeyo1R7eQj8Rke5dlPxX0KFwli8/bsCxpM/KbXO5y0qmV/5llQ3wpneDWcTYxa+4vn8iQ==} hasBin: true + local-pkg@1.1.1: + resolution: {integrity: sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==} + engines: {node: '>=14'} + locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -2875,6 +3303,9 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash-es@4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} @@ -2921,6 +3352,11 @@ packages: resolution: {integrity: sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ==} engines: {node: ^18.17.0 || >=20.5.0} + marked@15.0.12: + resolution: {integrity: sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==} + engines: {node: '>= 18'} + hasBin: true + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -2933,6 +3369,9 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + mermaid@11.8.0: + resolution: {integrity: sha512-uAZUwnBiqREZcUrFw3G5iQ5Pj3hTYUP95EZc3ec/nGBzHddJZydzYGE09tGZDBS1VoSoDn0symZ85FmypSTo5g==} + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} @@ -3027,6 +3466,9 @@ packages: engines: {node: '>=10'} hasBin: true + mlly@1.7.4: + resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} + mrmime@2.0.1: resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} engines: {node: '>=10'} @@ -3073,6 +3515,16 @@ packages: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} + ngx-markdown@20.0.0: + resolution: {integrity: sha512-AtB0EhYlfZbNBFzzhOkqxw5tIX+Z1rLqkRP207ee8c3QHQTn/uRmVVTMwE7LenF2ZOW11Brq/O8h6VfLy9FG+w==} + peerDependencies: + '@angular/common': ^20.0.0 + '@angular/core': ^20.0.0 + '@angular/platform-browser': ^20.0.0 + marked: ^15.0.0 + rxjs: ^6.5.3 || ^7.4.0 + zone.js: ~0.15.0 + node-addon-api@6.1.0: resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==} @@ -3231,6 +3683,9 @@ packages: package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + package-manager-detector@1.3.0: + resolution: {integrity: sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ==} + pacote@21.0.0: resolution: {integrity: sha512-lcqexq73AMv6QNLo7SOpz0JJoaGdS3rBFgF122NZVl1bApo2mfu+XzUBU/X/XsiJu+iUmKpekRayqQYAs+PhkA==} engines: {node: ^20.17.0 || >=22.9.0} @@ -3265,6 +3720,9 @@ packages: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} + path-data-parser@0.1.0: + resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -3324,6 +3782,12 @@ packages: resolution: {integrity: sha512-9rPDIPsCwOivatEZGM8+apgM7AiTDLSnpwMmLaSmdm2PeND8bFJzZLZZxyrJjLH8Xx/MpKoVaKf+vZOWALNHbw==} engines: {node: '>=20.x'} + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + pkg-types@2.2.0: + resolution: {integrity: sha512-2SM/GZGAEkPp3KWORxQZns4M+WSeXbC2HEvmOIJe3Cmiv6ieAJvdVhDldtHqM5J1Y7MrR1XhkBT/rMlhh9FdqQ==} + playwright-core@1.53.2: resolution: {integrity: sha512-ox/OytMy+2w1jcYEYlOo1Hhp8hZkLCximMTUTMBXjGUA1KoFfiSZ+DU+3a739jsPY0yoKH2TFy9S2fsJas8yAw==} engines: {node: '>=18'} @@ -3338,6 +3802,12 @@ packages: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} + points-on-curve@0.2.0: + resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==} + + points-on-path@0.2.1: + resolution: {integrity: sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==} + possible-typed-array-names@1.1.0: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} @@ -3353,6 +3823,20 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + prisma@6.11.1: + resolution: {integrity: sha512-VzJToRlV0s9Vu2bfqHiRJw73hZNCG/AyJeX+kopbu4GATTjTUdEWUteO3p4BLYoHpMS4o8pD3v6tF44BHNZI1w==} + engines: {node: '>=18.18'} + hasBin: true + peerDependencies: + typescript: '>=5.1.0' + peerDependenciesMeta: + typescript: + optional: true + + prismjs@1.30.0: + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} + engines: {node: '>=6'} + proc-log@5.0.0: resolution: {integrity: sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==} engines: {node: ^18.17.0 || >=20.5.0} @@ -3388,6 +3872,9 @@ packages: resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} engines: {node: '>=0.6'} + quansync@0.2.10: + resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -3467,6 +3954,9 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + resolve@1.22.10: resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} engines: {node: '>= 0.4'} @@ -3500,6 +3990,9 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true + robust-predicates@3.0.2: + resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + rollup@4.40.2: resolution: {integrity: sha512-tfUOg6DTP4rhQ3VjOO6B4wyrJnGOX85requAXvqYTHsOgb2TFJdZ3aWpT8W2kPoypSGP7dZUyzxJ9ee4buM5Fg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -3510,9 +4003,15 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + roughjs@4.6.6: + resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} @@ -3549,6 +4048,9 @@ packages: secure-json-parse@4.0.0: resolution: {integrity: sha512-dxtLJO6sc35jWidmLxo7ij+Eg48PM/kleBsxpC8QJE0qJICe+KawkDQmvCMZUr9u7WKVHgMW6vy3fQ7zMiFZMA==} + select@1.1.2: + resolution: {integrity: sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==} + semver@5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true @@ -3777,6 +4279,9 @@ packages: strip-literal@3.0.0: resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==} + stylis@4.3.6: + resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -3805,12 +4310,18 @@ packages: thread-stream@3.1.0: resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} + tiny-emitter@2.1.0: + resolution: {integrity: sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyexec@1.0.1: + resolution: {integrity: sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==} + tinyglobby@0.2.13: resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==} engines: {node: '>=12.0.0'} @@ -3863,12 +4374,21 @@ packages: peerDependencies: typescript: '>=4.8.4' + ts-dedent@2.2.0: + resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} + engines: {node: '>=6.10'} + tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsx@4.20.3: + resolution: {integrity: sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ==} + engines: {node: '>=18.0.0'} + hasBin: true + tuf-js@3.1.0: resolution: {integrity: sha512-3T3T04WzowbwV2FDiGXBbr81t64g1MUGGJRgT4x5o97N+8ArdhVCAF9IxFrxuSJmM3E5Asn7nKHkao0ibcZXAg==} engines: {node: ^18.17.0 || >=20.5.0} @@ -3956,6 +4476,9 @@ packages: resolution: {integrity: sha512-us1E3K+3jJppDBa3Tl0L3MOJiGhe1C6P0+nIvQAFYbxlMAx0h81eOwLmU57xgqToduDDPx3y5QsdjPfDu+FgOQ==} hasBin: true + ufo@1.6.1: + resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} @@ -3992,6 +4515,10 @@ packages: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} + uuid@11.1.0: + resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} + hasBin: true + validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} @@ -4120,6 +4647,26 @@ packages: resolution: {integrity: sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==} engines: {node: '>=0.10.0'} + vscode-jsonrpc@8.2.0: + resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} + engines: {node: '>=14.0.0'} + + vscode-languageserver-protocol@3.17.5: + resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} + + vscode-languageserver-textdocument@1.0.12: + resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} + + vscode-languageserver-types@3.17.5: + resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} + + vscode-languageserver@9.0.1: + resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} + hasBin: true + + vscode-uri@3.0.8: + resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} + watchpack@2.4.2: resolution: {integrity: sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==} engines: {node: '>=10.13.0'} @@ -4281,7 +4828,7 @@ snapshots: transitivePeerDependencies: - chokidar - '@angular/build@20.0.5(@angular/compiler-cli@20.0.6(@angular/compiler@20.0.6)(typescript@5.8.3))(@angular/compiler@20.0.6)(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.0.6(@angular/common@20.0.6(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.0.10)(chokidar@4.0.3)(jiti@1.21.7)(karma@6.4.4)(less@4.3.0)(postcss@8.5.6)(terser@5.39.1)(tslib@2.8.1)(typescript@5.8.3)(vitest@3.2.4(@types/node@24.0.10)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1))': + '@angular/build@20.0.5(@angular/compiler-cli@20.0.6(@angular/compiler@20.0.6)(typescript@5.8.3))(@angular/compiler@20.0.6)(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.0.6(@angular/common@20.0.6(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.0.10)(chokidar@4.0.3)(jiti@2.4.2)(karma@6.4.4)(less@4.3.0)(postcss@8.5.6)(terser@5.39.1)(tslib@2.8.1)(tsx@4.20.3)(typescript@5.8.3)(vitest@3.2.4(@types/node@24.0.10)(jiti@2.4.2)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(tsx@4.20.3))': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.2000.5(chokidar@4.0.3) @@ -4291,7 +4838,7 @@ snapshots: '@babel/helper-annotate-as-pure': 7.27.1 '@babel/helper-split-export-declaration': 7.24.7 '@inquirer/confirm': 5.1.10(@types/node@24.0.10) - '@vitejs/plugin-basic-ssl': 2.0.0(vite@6.3.5(@types/node@24.0.10)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)) + '@vitejs/plugin-basic-ssl': 2.0.0(vite@6.3.5(@types/node@24.0.10)(jiti@2.4.2)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(tsx@4.20.3)) beasties: 0.3.4 browserslist: 4.25.1 esbuild: 0.25.5 @@ -4311,7 +4858,7 @@ snapshots: tinyglobby: 0.2.13 tslib: 2.8.1 typescript: 5.8.3 - vite: 6.3.5(@types/node@24.0.10)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1) + vite: 6.3.5(@types/node@24.0.10)(jiti@2.4.2)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(tsx@4.20.3) watchpack: 2.4.2 optionalDependencies: '@angular/core': 20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1) @@ -4320,7 +4867,7 @@ snapshots: less: 4.3.0 lmdb: 3.3.0 postcss: 8.5.6 - vitest: 3.2.4(@types/node@24.0.10)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1) + vitest: 3.2.4(@types/node@24.0.10)(jiti@2.4.2)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(tsx@4.20.3) transitivePeerDependencies: - '@types/node' - chokidar @@ -4413,6 +4960,15 @@ snapshots: rxjs: 7.8.2 tslib: 2.8.1 + '@antfu/install-pkg@1.1.0': + dependencies: + package-manager-detector: 1.3.0 + tinyexec: 1.0.1 + optional: true + + '@antfu/utils@8.1.1': + optional: true + '@babel/code-frame@7.27.1': dependencies: '@babel/helper-validator-identifier': 7.27.1 @@ -4579,6 +5135,31 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 + '@braintree/sanitize-url@7.1.1': + optional: true + + '@chevrotain/cst-dts-gen@11.0.3': + dependencies: + '@chevrotain/gast': 11.0.3 + '@chevrotain/types': 11.0.3 + lodash-es: 4.17.21 + optional: true + + '@chevrotain/gast@11.0.3': + dependencies: + '@chevrotain/types': 11.0.3 + lodash-es: 4.17.21 + optional: true + + '@chevrotain/regexp-to-ast@11.0.3': + optional: true + + '@chevrotain/types@11.0.3': + optional: true + + '@chevrotain/utils@11.0.3': + optional: true + '@colors/colors@1.5.0': {} '@es-joy/jsdoccomment@0.49.0': @@ -4662,22 +5243,22 @@ snapshots: '@esbuild/win32-x64@0.25.5': optional: true - '@eslint-community/eslint-plugin-eslint-comments@4.4.1(eslint@9.30.1(jiti@1.21.7))': + '@eslint-community/eslint-plugin-eslint-comments@4.4.1(eslint@9.30.1(jiti@2.4.2))': dependencies: escape-string-regexp: 4.0.0 - eslint: 9.30.1(jiti@1.21.7) + eslint: 9.30.1(jiti@2.4.2) ignore: 5.3.2 - '@eslint-community/eslint-utils@4.7.0(eslint@9.30.1(jiti@1.21.7))': + '@eslint-community/eslint-utils@4.7.0(eslint@9.30.1(jiti@2.4.2))': dependencies: - eslint: 9.30.1(jiti@1.21.7) + eslint: 9.30.1(jiti@2.4.2) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} - '@eslint/compat@1.2.4(eslint@9.30.1(jiti@1.21.7))': + '@eslint/compat@1.2.4(eslint@9.30.1(jiti@2.4.2))': optionalDependencies: - eslint: 9.30.1(jiti@1.21.7) + eslint: 9.30.1(jiti@2.4.2) '@eslint/config-array@0.21.0': dependencies: @@ -4742,6 +5323,11 @@ snapshots: ajv-formats: 3.0.1(ajv@8.17.1) fast-uri: 3.0.6 + '@fastify/cors@11.0.1': + dependencies: + fastify-plugin: 5.0.1 + toad-cache: 3.7.0 + '@fastify/error@4.2.0': {} '@fastify/fast-json-stringify-compiler@5.0.3': @@ -4772,6 +5358,23 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} + '@iconify/types@2.0.0': + optional: true + + '@iconify/utils@2.3.0': + dependencies: + '@antfu/install-pkg': 1.1.0 + '@antfu/utils': 8.1.1 + '@iconify/types': 2.0.0 + debug: 4.4.1 + globals: 15.14.0 + kolorist: 1.8.0 + local-pkg: 1.1.1 + mlly: 1.7.4 + transitivePeerDependencies: + - supports-color + optional: true + '@inquirer/checkbox@4.1.9(@types/node@24.0.10)': dependencies: '@inquirer/core': 10.1.14(@types/node@24.0.10) @@ -4960,6 +5563,11 @@ snapshots: '@lmdb/lmdb-win32-x64@3.3.0': optional: true + '@mermaid-js/parser@0.6.0': + dependencies: + langium: 3.3.1 + optional: true + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': optional: true @@ -5046,29 +5654,29 @@ snapshots: '@napi-rs/nice-win32-x64-msvc': 1.0.2 optional: true - '@nhcarrigan/eslint-config@5.2.0(@typescript-eslint/utils@8.35.1(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.30.1(jiti@1.21.7))(playwright@1.53.2)(react@19.1.0)(typescript@5.8.3)(vitest@3.2.4(@types/node@24.0.10)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1))': + '@nhcarrigan/eslint-config@5.2.0(@typescript-eslint/utils@8.35.1(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3))(eslint@9.30.1(jiti@2.4.2))(playwright@1.53.2)(react@19.1.0)(typescript@5.8.3)(vitest@3.2.4(@types/node@24.0.10)(jiti@2.4.2)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(tsx@4.20.3))': dependencies: - '@eslint-community/eslint-plugin-eslint-comments': 4.4.1(eslint@9.30.1(jiti@1.21.7)) - '@eslint/compat': 1.2.4(eslint@9.30.1(jiti@1.21.7)) + '@eslint-community/eslint-plugin-eslint-comments': 4.4.1(eslint@9.30.1(jiti@2.4.2)) + '@eslint/compat': 1.2.4(eslint@9.30.1(jiti@2.4.2)) '@eslint/eslintrc': 3.2.0 '@eslint/js': 9.17.0 - '@stylistic/eslint-plugin': 2.12.1(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3) - '@typescript-eslint/eslint-plugin': 8.19.0(@typescript-eslint/parser@8.19.0(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3) - '@typescript-eslint/parser': 8.19.0(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3) - '@vitest/eslint-plugin': 1.1.24(@typescript-eslint/utils@8.35.1(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3)(vitest@3.2.4(@types/node@24.0.10)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)) - eslint: 9.30.1(jiti@1.21.7) - eslint-plugin-deprecation: 3.0.0(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.19.0(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.30.1(jiti@1.21.7)) - eslint-plugin-jsdoc: 50.6.1(eslint@9.30.1(jiti@1.21.7)) - eslint-plugin-playwright: 2.1.0(eslint@9.30.1(jiti@1.21.7)) - eslint-plugin-react: 7.37.3(eslint@9.30.1(jiti@1.21.7)) + '@stylistic/eslint-plugin': 2.12.1(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/eslint-plugin': 8.19.0(@typescript-eslint/parser@8.19.0(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3))(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/parser': 8.19.0(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3) + '@vitest/eslint-plugin': 1.1.24(@typescript-eslint/utils@8.35.1(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3))(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3)(vitest@3.2.4(@types/node@24.0.10)(jiti@2.4.2)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(tsx@4.20.3)) + eslint: 9.30.1(jiti@2.4.2) + eslint-plugin-deprecation: 3.0.0(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.19.0(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3))(eslint@9.30.1(jiti@2.4.2)) + eslint-plugin-jsdoc: 50.6.1(eslint@9.30.1(jiti@2.4.2)) + eslint-plugin-playwright: 2.1.0(eslint@9.30.1(jiti@2.4.2)) + eslint-plugin-react: 7.37.3(eslint@9.30.1(jiti@2.4.2)) eslint-plugin-sort-keys-fix: 1.1.2 - eslint-plugin-unicorn: 56.0.1(eslint@9.30.1(jiti@1.21.7)) + eslint-plugin-unicorn: 56.0.1(eslint@9.30.1(jiti@2.4.2)) globals: 15.14.0 playwright: 1.53.2 react: 19.1.0 typescript: 5.8.3 - vitest: 3.2.4(@types/node@24.0.10)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1) + vitest: 3.2.4(@types/node@24.0.10)(jiti@2.4.2)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(tsx@4.20.3) transitivePeerDependencies: - '@typescript-eslint/utils' - eslint-import-resolver-typescript @@ -5218,6 +5826,36 @@ snapshots: '@pkgr/core@0.1.2': {} + '@prisma/client@6.11.1(prisma@6.11.1(typescript@5.8.3))(typescript@5.8.3)': + optionalDependencies: + prisma: 6.11.1(typescript@5.8.3) + typescript: 5.8.3 + + '@prisma/config@6.11.1': + dependencies: + jiti: 2.4.2 + + '@prisma/debug@6.11.1': {} + + '@prisma/engines-version@6.11.1-1.f40f79ec31188888a2e33acda0ecc8fd10a853a9': {} + + '@prisma/engines@6.11.1': + dependencies: + '@prisma/debug': 6.11.1 + '@prisma/engines-version': 6.11.1-1.f40f79ec31188888a2e33acda0ecc8fd10a853a9 + '@prisma/fetch-engine': 6.11.1 + '@prisma/get-platform': 6.11.1 + + '@prisma/fetch-engine@6.11.1': + dependencies: + '@prisma/debug': 6.11.1 + '@prisma/engines-version': 6.11.1-1.f40f79ec31188888a2e33acda0ecc8fd10a853a9 + '@prisma/get-platform': 6.11.1 + + '@prisma/get-platform@6.11.1': + dependencies: + '@prisma/debug': 6.11.1 + '@rollup/rollup-android-arm-eabi@4.40.2': optional: true @@ -5382,10 +6020,10 @@ snapshots: '@socket.io/component-emitter@3.1.2': {} - '@stylistic/eslint-plugin@2.12.1(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3)': + '@stylistic/eslint-plugin@2.12.1(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3)': dependencies: - '@typescript-eslint/utils': 8.35.1(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3) - eslint: 9.30.1(jiti@1.21.7) + '@typescript-eslint/utils': 8.35.1(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3) + eslint: 9.30.1(jiti@2.4.2) eslint-visitor-keys: 4.2.1 espree: 10.4.0 estraverse: 5.3.0 @@ -5409,12 +6047,163 @@ snapshots: dependencies: '@types/node': 24.0.10 + '@types/d3-array@3.2.1': + optional: true + + '@types/d3-axis@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + optional: true + + '@types/d3-brush@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + optional: true + + '@types/d3-chord@3.0.6': + optional: true + + '@types/d3-color@3.1.3': + optional: true + + '@types/d3-contour@3.0.6': + dependencies: + '@types/d3-array': 3.2.1 + '@types/geojson': 7946.0.16 + optional: true + + '@types/d3-delaunay@6.0.4': + optional: true + + '@types/d3-dispatch@3.0.6': + optional: true + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + optional: true + + '@types/d3-dsv@3.0.7': + optional: true + + '@types/d3-ease@3.0.2': + optional: true + + '@types/d3-fetch@3.0.7': + dependencies: + '@types/d3-dsv': 3.0.7 + optional: true + + '@types/d3-force@3.0.10': + optional: true + + '@types/d3-format@3.0.4': + optional: true + + '@types/d3-geo@3.1.0': + dependencies: + '@types/geojson': 7946.0.16 + optional: true + + '@types/d3-hierarchy@3.1.7': + optional: true + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + optional: true + + '@types/d3-path@3.1.1': + optional: true + + '@types/d3-polygon@3.0.2': + optional: true + + '@types/d3-quadtree@3.0.6': + optional: true + + '@types/d3-random@3.0.3': + optional: true + + '@types/d3-scale-chromatic@3.1.0': + optional: true + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + optional: true + + '@types/d3-selection@3.0.11': + optional: true + + '@types/d3-shape@3.1.7': + dependencies: + '@types/d3-path': 3.1.1 + optional: true + + '@types/d3-time-format@4.0.3': + optional: true + + '@types/d3-time@3.0.4': + optional: true + + '@types/d3-timer@3.0.2': + optional: true + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + optional: true + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + optional: true + + '@types/d3@7.4.3': + dependencies: + '@types/d3-array': 3.2.1 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.6 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.1 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.3 + '@types/d3-scale': 4.0.9 + '@types/d3-scale-chromatic': 3.1.0 + '@types/d3-selection': 3.0.11 + '@types/d3-shape': 3.1.7 + '@types/d3-time': 3.0.4 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + optional: true + '@types/deep-eql@4.0.2': {} '@types/estree@1.0.7': {} '@types/estree@1.0.8': {} + '@types/geojson@7946.0.16': + optional: true + '@types/jasmine@5.1.8': {} '@types/json-schema@7.0.15': {} @@ -5427,15 +6216,18 @@ snapshots: '@types/normalize-package-data@2.4.4': {} - '@typescript-eslint/eslint-plugin@8.19.0(@typescript-eslint/parser@8.19.0(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3)': + '@types/trusted-types@2.0.7': + optional: true + + '@typescript-eslint/eslint-plugin@8.19.0(@typescript-eslint/parser@8.19.0(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3))(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.19.0(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3) + '@typescript-eslint/parser': 8.19.0(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3) '@typescript-eslint/scope-manager': 8.19.0 - '@typescript-eslint/type-utils': 8.19.0(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3) - '@typescript-eslint/utils': 8.19.0(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3) + '@typescript-eslint/type-utils': 8.19.0(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/utils': 8.19.0(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3) '@typescript-eslint/visitor-keys': 8.19.0 - eslint: 9.30.1(jiti@1.21.7) + eslint: 9.30.1(jiti@2.4.2) graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 @@ -5444,14 +6236,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.19.0(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3)': + '@typescript-eslint/parser@8.19.0(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3)': dependencies: '@typescript-eslint/scope-manager': 8.19.0 '@typescript-eslint/types': 8.19.0 '@typescript-eslint/typescript-estree': 8.19.0(typescript@5.8.3) '@typescript-eslint/visitor-keys': 8.19.0 debug: 4.4.1 - eslint: 9.30.1(jiti@1.21.7) + eslint: 9.30.1(jiti@2.4.2) typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -5484,12 +6276,12 @@ snapshots: dependencies: typescript: 5.8.3 - '@typescript-eslint/type-utils@8.19.0(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3)': + '@typescript-eslint/type-utils@8.19.0(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3)': dependencies: '@typescript-eslint/typescript-estree': 8.19.0(typescript@5.8.3) - '@typescript-eslint/utils': 8.19.0(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3) + '@typescript-eslint/utils': 8.19.0(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3) debug: 4.4.1 - eslint: 9.30.1(jiti@1.21.7) + eslint: 9.30.1(jiti@2.4.2) ts-api-utils: 1.4.3(typescript@5.8.3) typescript: 5.8.3 transitivePeerDependencies: @@ -5546,35 +6338,35 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@7.18.0(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3)': + '@typescript-eslint/utils@7.18.0(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3)': dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.30.1(jiti@1.21.7)) + '@eslint-community/eslint-utils': 4.7.0(eslint@9.30.1(jiti@2.4.2)) '@typescript-eslint/scope-manager': 7.18.0 '@typescript-eslint/types': 7.18.0 '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.8.3) - eslint: 9.30.1(jiti@1.21.7) + eslint: 9.30.1(jiti@2.4.2) transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/utils@8.19.0(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3)': + '@typescript-eslint/utils@8.19.0(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3)': dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.30.1(jiti@1.21.7)) + '@eslint-community/eslint-utils': 4.7.0(eslint@9.30.1(jiti@2.4.2)) '@typescript-eslint/scope-manager': 8.19.0 '@typescript-eslint/types': 8.19.0 '@typescript-eslint/typescript-estree': 8.19.0(typescript@5.8.3) - eslint: 9.30.1(jiti@1.21.7) + eslint: 9.30.1(jiti@2.4.2) typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.35.1(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3)': + '@typescript-eslint/utils@8.35.1(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3)': dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.30.1(jiti@1.21.7)) + '@eslint-community/eslint-utils': 4.7.0(eslint@9.30.1(jiti@2.4.2)) '@typescript-eslint/scope-manager': 8.35.1 '@typescript-eslint/types': 8.35.1 '@typescript-eslint/typescript-estree': 8.35.1(typescript@5.8.3) - eslint: 9.30.1(jiti@1.21.7) + eslint: 9.30.1(jiti@2.4.2) typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -5594,17 +6386,17 @@ snapshots: '@typescript-eslint/types': 8.35.1 eslint-visitor-keys: 4.2.1 - '@vitejs/plugin-basic-ssl@2.0.0(vite@6.3.5(@types/node@24.0.10)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1))': + '@vitejs/plugin-basic-ssl@2.0.0(vite@6.3.5(@types/node@24.0.10)(jiti@2.4.2)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(tsx@4.20.3))': dependencies: - vite: 6.3.5(@types/node@24.0.10)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1) + vite: 6.3.5(@types/node@24.0.10)(jiti@2.4.2)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(tsx@4.20.3) - '@vitest/eslint-plugin@1.1.24(@typescript-eslint/utils@8.35.1(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3)(vitest@3.2.4(@types/node@24.0.10)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1))': + '@vitest/eslint-plugin@1.1.24(@typescript-eslint/utils@8.35.1(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3))(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3)(vitest@3.2.4(@types/node@24.0.10)(jiti@2.4.2)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(tsx@4.20.3))': dependencies: - '@typescript-eslint/utils': 8.35.1(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3) - eslint: 9.30.1(jiti@1.21.7) + '@typescript-eslint/utils': 8.35.1(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3) + eslint: 9.30.1(jiti@2.4.2) optionalDependencies: typescript: 5.8.3 - vitest: 3.2.4(@types/node@24.0.10)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1) + vitest: 3.2.4(@types/node@24.0.10)(jiti@2.4.2)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(tsx@4.20.3) '@vitest/expect@3.2.4': dependencies: @@ -5614,13 +6406,13 @@ snapshots: chai: 5.2.0 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(vite@7.0.1(@types/node@24.0.10)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1))': + '@vitest/mocker@3.2.4(vite@7.0.1(@types/node@24.0.10)(jiti@2.4.2)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(tsx@4.20.3))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - vite: 7.0.1(@types/node@24.0.10)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1) + vite: 7.0.1(@types/node@24.0.10)(jiti@2.4.2)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(tsx@4.20.3) '@vitest/pretty-format@3.2.4': dependencies: @@ -5921,6 +6713,22 @@ snapshots: check-error@2.1.1: {} + chevrotain-allstar@0.3.1(chevrotain@11.0.3): + dependencies: + chevrotain: 11.0.3 + lodash-es: 4.17.21 + optional: true + + chevrotain@11.0.3: + dependencies: + '@chevrotain/cst-dts-gen': 11.0.3 + '@chevrotain/gast': 11.0.3 + '@chevrotain/regexp-to-ast': 11.0.3 + '@chevrotain/types': 11.0.3 + '@chevrotain/utils': 11.0.3 + lodash-es: 4.17.21 + optional: true + chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -5960,6 +6768,13 @@ snapshots: cli-width@4.1.0: {} + clipboard@2.0.11: + dependencies: + good-listener: 1.2.2 + select: 1.1.2 + tiny-emitter: 2.1.0 + optional: true + cliui@7.0.4: dependencies: string-width: 4.2.3 @@ -5989,10 +6804,22 @@ snapshots: commander@2.20.3: optional: true + commander@7.2.0: + optional: true + + commander@8.3.0: + optional: true + comment-parser@1.4.1: {} concat-map@0.0.1: {} + confbox@0.1.8: + optional: true + + confbox@0.2.2: + optional: true + connect@3.7.0: dependencies: debug: 2.6.9 @@ -6026,6 +6853,16 @@ snapshots: object-assign: 4.1.1 vary: 1.1.2 + cose-base@1.0.3: + dependencies: + layout-base: 1.0.2 + optional: true + + cose-base@2.2.0: + dependencies: + layout-base: 2.0.1 + optional: true + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -6044,6 +6881,229 @@ snapshots: custom-event@1.0.1: {} + cytoscape-cose-bilkent@4.1.0(cytoscape@3.32.0): + dependencies: + cose-base: 1.0.3 + cytoscape: 3.32.0 + optional: true + + cytoscape-fcose@2.2.0(cytoscape@3.32.0): + dependencies: + cose-base: 2.2.0 + cytoscape: 3.32.0 + optional: true + + cytoscape@3.32.0: + optional: true + + d3-array@2.12.1: + dependencies: + internmap: 1.0.1 + optional: true + + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + optional: true + + d3-axis@3.0.0: + optional: true + + d3-brush@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + optional: true + + d3-chord@3.0.1: + dependencies: + d3-path: 3.1.0 + optional: true + + d3-color@3.1.0: + optional: true + + d3-contour@4.0.2: + dependencies: + d3-array: 3.2.4 + optional: true + + d3-delaunay@6.0.4: + dependencies: + delaunator: 5.0.1 + optional: true + + d3-dispatch@3.0.1: + optional: true + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + optional: true + + d3-dsv@3.0.1: + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + optional: true + + d3-ease@3.0.1: + optional: true + + d3-fetch@3.0.1: + dependencies: + d3-dsv: 3.0.1 + optional: true + + d3-force@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + optional: true + + d3-format@3.1.0: + optional: true + + d3-geo@3.1.1: + dependencies: + d3-array: 3.2.4 + optional: true + + d3-hierarchy@3.1.2: + optional: true + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + optional: true + + d3-path@1.0.9: + optional: true + + d3-path@3.1.0: + optional: true + + d3-polygon@3.0.1: + optional: true + + d3-quadtree@3.0.1: + optional: true + + d3-random@3.0.1: + optional: true + + d3-sankey@0.12.3: + dependencies: + d3-array: 2.12.1 + d3-shape: 1.3.7 + optional: true + + d3-scale-chromatic@3.1.0: + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + optional: true + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.0 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + optional: true + + d3-selection@3.0.0: + optional: true + + d3-shape@1.3.7: + dependencies: + d3-path: 1.0.9 + optional: true + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + optional: true + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + optional: true + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + optional: true + + d3-timer@3.0.1: + optional: true + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + optional: true + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + optional: true + + d3@7.9.0: + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.0 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1(d3-selection@3.0.0) + d3-zoom: 3.0.0 + optional: true + + dagre-d3-es@7.0.11: + dependencies: + d3: 7.9.0 + lodash-es: 4.17.21 + optional: true + data-view-buffer@1.0.2: dependencies: call-bound: 1.0.4 @@ -6064,6 +7124,9 @@ snapshots: date-format@4.0.14: {} + dayjs@1.11.13: + optional: true + debug@2.6.9: dependencies: ms: 2.0.0 @@ -6096,6 +7159,14 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + delaunator@5.0.1: + dependencies: + robust-predicates: 3.0.2 + optional: true + + delegate@3.2.0: + optional: true + depd@2.0.0: {} dequal@2.0.3: {} @@ -6137,6 +7208,11 @@ snapshots: dependencies: domelementtype: 2.3.0 + dompurify@3.2.6: + optionalDependencies: + '@types/trusted-types': 2.0.7 + optional: true + domutils@3.2.2: dependencies: dom-serializer: 2.0.0 @@ -6161,6 +7237,9 @@ snapshots: emoji-regex@9.2.2: {} + emoji-toolkit@9.0.1: + optional: true + encodeurl@1.0.2: {} encoding@0.1.13: @@ -6359,27 +7438,27 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.19.0(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@9.30.1(jiti@1.21.7)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.19.0(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@9.30.1(jiti@2.4.2)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.19.0(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3) - eslint: 9.30.1(jiti@1.21.7) + '@typescript-eslint/parser': 8.19.0(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3) + eslint: 9.30.1(jiti@2.4.2) eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-deprecation@3.0.0(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3): + eslint-plugin-deprecation@3.0.0(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3): dependencies: - '@typescript-eslint/utils': 7.18.0(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3) - eslint: 9.30.1(jiti@1.21.7) + '@typescript-eslint/utils': 7.18.0(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3) + eslint: 9.30.1(jiti@2.4.2) ts-api-utils: 1.4.3(typescript@5.8.3) tslib: 2.8.1 typescript: 5.8.3 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.19.0(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.30.1(jiti@1.21.7)): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.19.0(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3))(eslint@9.30.1(jiti@2.4.2)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -6388,9 +7467,9 @@ snapshots: array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.30.1(jiti@1.21.7) + eslint: 9.30.1(jiti@2.4.2) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.19.0(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@9.30.1(jiti@1.21.7)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.19.0(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@9.30.1(jiti@2.4.2)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -6402,20 +7481,20 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.19.0(eslint@9.30.1(jiti@1.21.7))(typescript@5.8.3) + '@typescript-eslint/parser': 8.19.0(eslint@9.30.1(jiti@2.4.2))(typescript@5.8.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-jsdoc@50.6.1(eslint@9.30.1(jiti@1.21.7)): + eslint-plugin-jsdoc@50.6.1(eslint@9.30.1(jiti@2.4.2)): dependencies: '@es-joy/jsdoccomment': 0.49.0 are-docs-informative: 0.0.2 comment-parser: 1.4.1 debug: 4.4.1 escape-string-regexp: 4.0.0 - eslint: 9.30.1(jiti@1.21.7) + eslint: 9.30.1(jiti@2.4.2) espree: 10.4.0 esquery: 1.6.0 parse-imports: 2.2.1 @@ -6425,12 +7504,12 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-playwright@2.1.0(eslint@9.30.1(jiti@1.21.7)): + eslint-plugin-playwright@2.1.0(eslint@9.30.1(jiti@2.4.2)): dependencies: - eslint: 9.30.1(jiti@1.21.7) + eslint: 9.30.1(jiti@2.4.2) globals: 13.24.0 - eslint-plugin-react@7.37.3(eslint@9.30.1(jiti@1.21.7)): + eslint-plugin-react@7.37.3(eslint@9.30.1(jiti@2.4.2)): dependencies: array-includes: 3.1.9 array.prototype.findlast: 1.2.5 @@ -6438,7 +7517,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.2.1 - eslint: 9.30.1(jiti@1.21.7) + eslint: 9.30.1(jiti@2.4.2) estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 @@ -6459,14 +7538,14 @@ snapshots: natural-compare: 1.4.0 requireindex: 1.2.0 - eslint-plugin-unicorn@56.0.1(eslint@9.30.1(jiti@1.21.7)): + eslint-plugin-unicorn@56.0.1(eslint@9.30.1(jiti@2.4.2)): dependencies: '@babel/helper-validator-identifier': 7.27.1 - '@eslint-community/eslint-utils': 4.7.0(eslint@9.30.1(jiti@1.21.7)) + '@eslint-community/eslint-utils': 4.7.0(eslint@9.30.1(jiti@2.4.2)) ci-info: 4.2.0 clean-regexp: 1.0.0 core-js-compat: 3.43.0 - eslint: 9.30.1(jiti@1.21.7) + eslint: 9.30.1(jiti@2.4.2) esquery: 1.6.0 globals: 15.14.0 indent-string: 4.0.0 @@ -6490,9 +7569,9 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint@9.30.1(jiti@1.21.7): + eslint@9.30.1(jiti@2.4.2): dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.30.1(jiti@1.21.7)) + '@eslint-community/eslint-utils': 4.7.0(eslint@9.30.1(jiti@2.4.2)) '@eslint-community/regexpp': 4.12.1 '@eslint/config-array': 0.21.0 '@eslint/config-helpers': 0.3.0 @@ -6528,7 +7607,7 @@ snapshots: natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: - jiti: 1.21.7 + jiti: 2.4.2 transitivePeerDependencies: - supports-color @@ -6568,6 +7647,9 @@ snapshots: exponential-backoff@3.1.2: {} + exsolve@1.0.7: + optional: true + extend@3.0.2: {} external-editor@3.1.0: @@ -6609,6 +7691,8 @@ snapshots: fast-uri@3.0.6: {} + fastify-plugin@5.0.1: {} + fastify@5.4.0: dependencies: '@fastify/ajv-compiler': 4.0.2 @@ -6754,6 +7838,10 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 + get-tsconfig@4.10.1: + dependencies: + resolve-pkg-maps: 1.0.0 + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -6804,12 +7892,20 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 + good-listener@1.2.2: + dependencies: + delegate: 3.2.0 + optional: true + gopd@1.2.0: {} graceful-fs@4.2.11: {} graphemer@1.4.0: {} + hachure-fill@0.5.2: + optional: true + has-bigints@1.1.0: {} has-flag@4.0.0: {} @@ -6923,6 +8019,12 @@ snapshots: hasown: 2.0.2 side-channel: 1.1.0 + internmap@1.0.1: + optional: true + + internmap@2.0.3: + optional: true + ip-address@9.0.5: dependencies: jsbn: 1.1.0 @@ -7132,8 +8234,7 @@ snapshots: jasmine-core@5.8.0: {} - jiti@1.21.7: - optional: true + jiti@2.4.2: {} js-tokens@4.0.0: {} @@ -7246,10 +8347,36 @@ snapshots: - supports-color - utf-8-validate + katex@0.16.22: + dependencies: + commander: 8.3.0 + optional: true + keyv@4.5.4: dependencies: json-buffer: 3.0.1 + khroma@2.1.0: + optional: true + + kolorist@1.8.0: + optional: true + + langium@3.3.1: + dependencies: + chevrotain: 11.0.3 + chevrotain-allstar: 0.3.1(chevrotain@11.0.3) + vscode-languageserver: 9.0.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.0.8 + optional: true + + layout-base@1.0.2: + optional: true + + layout-base@2.0.1: + optional: true + less@4.3.0: dependencies: copy-anything: 2.0.6 @@ -7304,6 +8431,13 @@ snapshots: '@lmdb/lmdb-win32-x64': 3.3.0 optional: true + local-pkg@1.1.1: + dependencies: + mlly: 1.7.4 + pkg-types: 2.2.0 + quansync: 0.2.10 + optional: true + locate-path@5.0.0: dependencies: p-locate: 4.1.0 @@ -7312,6 +8446,9 @@ snapshots: dependencies: p-locate: 5.0.0 + lodash-es@4.17.21: + optional: true + lodash.merge@4.6.2: {} lodash@4.17.21: {} @@ -7381,12 +8518,40 @@ snapshots: transitivePeerDependencies: - supports-color + marked@15.0.12: {} + math-intrinsics@1.1.0: {} media-typer@0.3.0: {} merge2@1.4.1: {} + mermaid@11.8.0: + dependencies: + '@braintree/sanitize-url': 7.1.1 + '@iconify/utils': 2.3.0 + '@mermaid-js/parser': 0.6.0 + '@types/d3': 7.4.3 + cytoscape: 3.32.0 + cytoscape-cose-bilkent: 4.1.0(cytoscape@3.32.0) + cytoscape-fcose: 2.2.0(cytoscape@3.32.0) + d3: 7.9.0 + d3-sankey: 0.12.3 + dagre-d3-es: 7.0.11 + dayjs: 1.11.13 + dompurify: 3.2.6 + katex: 0.16.22 + khroma: 2.1.0 + lodash-es: 4.17.21 + marked: 15.0.12 + roughjs: 4.6.6 + stylis: 4.3.6 + ts-dedent: 2.2.0 + uuid: 11.1.0 + transitivePeerDependencies: + - supports-color + optional: true + micromatch@4.0.8: dependencies: braces: 3.0.3 @@ -7466,6 +8631,14 @@ snapshots: mkdirp@3.0.1: {} + mlly@1.7.4: + dependencies: + acorn: 8.15.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.1 + optional: true + mrmime@2.0.1: {} ms@2.0.0: {} @@ -7507,6 +8680,24 @@ snapshots: negotiator@1.0.0: {} + ngx-markdown@20.0.0(@angular/common@20.0.6(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.0.6(@angular/common@20.0.6(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1)))(marked@15.0.12)(rxjs@7.8.2)(zone.js@0.15.1): + dependencies: + '@angular/common': 20.0.6(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) + '@angular/core': 20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/platform-browser': 20.0.6(@angular/common@20.0.6(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.0.6(@angular/compiler@20.0.6)(rxjs@7.8.2)(zone.js@0.15.1)) + marked: 15.0.12 + rxjs: 7.8.2 + tslib: 2.8.1 + zone.js: 0.15.1 + optionalDependencies: + clipboard: 2.0.11 + emoji-toolkit: 9.0.1 + katex: 0.16.22 + mermaid: 11.8.0 + prismjs: 1.30.0 + transitivePeerDependencies: + - supports-color + node-addon-api@6.1.0: optional: true @@ -7707,6 +8898,9 @@ snapshots: package-json-from-dist@1.0.1: {} + package-manager-detector@1.3.0: + optional: true + pacote@21.0.0: dependencies: '@npmcli/git': 6.0.3 @@ -7764,6 +8958,9 @@ snapshots: parseurl@1.3.3: {} + path-data-parser@0.1.0: + optional: true + path-exists@4.0.0: {} path-is-absolute@1.0.1: {} @@ -7816,6 +9013,20 @@ snapshots: optionalDependencies: '@napi-rs/nice': 1.0.2 + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.7.4 + pathe: 2.0.3 + optional: true + + pkg-types@2.2.0: + dependencies: + confbox: 0.2.2 + exsolve: 1.0.7 + pathe: 2.0.3 + optional: true + playwright-core@1.53.2: {} playwright@1.53.2: @@ -7826,6 +9037,15 @@ snapshots: pluralize@8.0.0: {} + points-on-curve@0.2.0: + optional: true + + points-on-path@0.2.1: + dependencies: + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + optional: true + possible-typed-array-names@1.1.0: {} postcss-media-query-parser@0.2.3: {} @@ -7838,6 +9058,16 @@ snapshots: prelude-ls@1.2.1: {} + prisma@6.11.1(typescript@5.8.3): + dependencies: + '@prisma/config': 6.11.1 + '@prisma/engines': 6.11.1 + optionalDependencies: + typescript: 5.8.3 + + prismjs@1.30.0: + optional: true + proc-log@5.0.0: {} process-warning@4.0.1: {} @@ -7868,6 +9098,9 @@ snapshots: dependencies: side-channel: 1.1.0 + quansync@0.2.10: + optional: true + queue-microtask@1.2.3: {} quick-format-unescaped@4.0.4: {} @@ -7944,6 +9177,8 @@ snapshots: resolve-from@4.0.0: {} + resolve-pkg-maps@1.0.0: {} + resolve@1.22.10: dependencies: is-core-module: 2.16.1 @@ -7973,6 +9208,9 @@ snapshots: dependencies: glob: 7.2.3 + robust-predicates@3.0.2: + optional: true + rollup@4.40.2: dependencies: '@types/estree': 1.0.7 @@ -8025,10 +9263,21 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.44.1 fsevents: 2.3.3 + roughjs@4.6.6: + dependencies: + hachure-fill: 0.5.2 + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + points-on-path: 0.2.1 + optional: true + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 + rw@1.3.3: + optional: true + rxjs@7.8.2: dependencies: tslib: 2.8.1 @@ -8073,6 +9322,9 @@ snapshots: secure-json-parse@4.0.0: {} + select@1.1.2: + optional: true + semver@5.7.2: {} semver@6.3.1: {} @@ -8360,6 +9612,9 @@ snapshots: dependencies: js-tokens: 9.0.1 + stylis@4.3.6: + optional: true + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -8401,10 +9656,16 @@ snapshots: dependencies: real-require: 0.2.0 + tiny-emitter@2.1.0: + optional: true + tinybench@2.9.0: {} tinyexec@0.3.2: {} + tinyexec@1.0.1: + optional: true + tinyglobby@0.2.13: dependencies: fdir: 6.4.6(picomatch@4.0.2) @@ -8443,6 +9704,9 @@ snapshots: dependencies: typescript: 5.8.3 + ts-dedent@2.2.0: + optional: true + tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29 @@ -8452,6 +9716,13 @@ snapshots: tslib@2.8.1: {} + tsx@4.20.3: + dependencies: + esbuild: 0.25.5 + get-tsconfig: 4.10.1 + optionalDependencies: + fsevents: 2.3.3 + tuf-js@3.1.0: dependencies: '@tufjs/models': 3.0.1 @@ -8541,6 +9812,9 @@ snapshots: ua-parser-js@0.7.40: {} + ufo@1.6.1: + optional: true + unbox-primitive@1.1.0: dependencies: call-bound: 1.0.4 @@ -8574,6 +9848,9 @@ snapshots: utils-merge@1.0.1: {} + uuid@11.1.0: + optional: true + validate-npm-package-license@3.0.4: dependencies: spdx-correct: 3.2.0 @@ -8583,13 +9860,13 @@ snapshots: vary@1.1.2: {} - vite-node@3.2.4(@types/node@24.0.10)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1): + vite-node@3.2.4(@types/node@24.0.10)(jiti@2.4.2)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(tsx@4.20.3): dependencies: cac: 6.7.14 debug: 4.4.1 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.0.1(@types/node@24.0.10)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1) + vite: 7.0.1(@types/node@24.0.10)(jiti@2.4.2)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(tsx@4.20.3) transitivePeerDependencies: - '@types/node' - jiti @@ -8604,7 +9881,7 @@ snapshots: - tsx - yaml - vite@6.3.5(@types/node@24.0.10)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1): + vite@6.3.5(@types/node@24.0.10)(jiti@2.4.2)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(tsx@4.20.3): dependencies: esbuild: 0.25.5 fdir: 6.4.6(picomatch@4.0.2) @@ -8615,12 +9892,13 @@ snapshots: optionalDependencies: '@types/node': 24.0.10 fsevents: 2.3.3 - jiti: 1.21.7 + jiti: 2.4.2 less: 4.3.0 sass: 1.88.0 terser: 5.39.1 + tsx: 4.20.3 - vite@7.0.1(@types/node@24.0.10)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1): + vite@7.0.1(@types/node@24.0.10)(jiti@2.4.2)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(tsx@4.20.3): dependencies: esbuild: 0.25.5 fdir: 6.4.6(picomatch@4.0.2) @@ -8631,16 +9909,17 @@ snapshots: optionalDependencies: '@types/node': 24.0.10 fsevents: 2.3.3 - jiti: 1.21.7 + jiti: 2.4.2 less: 4.3.0 sass: 1.88.0 terser: 5.39.1 + tsx: 4.20.3 - vitest@3.2.4(@types/node@24.0.10)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1): + vitest@3.2.4(@types/node@24.0.10)(jiti@2.4.2)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(tsx@4.20.3): dependencies: '@types/chai': 5.2.2 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.0.1(@types/node@24.0.10)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)) + '@vitest/mocker': 3.2.4(vite@7.0.1(@types/node@24.0.10)(jiti@2.4.2)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(tsx@4.20.3)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -8658,8 +9937,8 @@ snapshots: tinyglobby: 0.2.14 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.0.1(@types/node@24.0.10)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1) - vite-node: 3.2.4(@types/node@24.0.10)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1) + vite: 7.0.1(@types/node@24.0.10)(jiti@2.4.2)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(tsx@4.20.3) + vite-node: 3.2.4(@types/node@24.0.10)(jiti@2.4.2)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(tsx@4.20.3) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.0.10 @@ -8679,6 +9958,29 @@ snapshots: void-elements@2.0.1: {} + vscode-jsonrpc@8.2.0: + optional: true + + vscode-languageserver-protocol@3.17.5: + dependencies: + vscode-jsonrpc: 8.2.0 + vscode-languageserver-types: 3.17.5 + optional: true + + vscode-languageserver-textdocument@1.0.12: + optional: true + + vscode-languageserver-types@3.17.5: + optional: true + + vscode-languageserver@9.0.1: + dependencies: + vscode-languageserver-protocol: 3.17.5 + optional: true + + vscode-uri@3.0.8: + optional: true + watchpack@2.4.2: dependencies: glob-to-regexp: 0.4.1 diff --git a/server/dev.env b/server/dev.env new file mode 100644 index 0000000..547fe45 --- /dev/null +++ b/server/dev.env @@ -0,0 +1,5 @@ +LOG_TOKEN="op://Environment Variables - Naomi/Alert Server/api_auth" +MONGO_URI="op://Environment Variables - Naomi/Hikari/mongo_uri" +DISCORD_TOKEN="op://Environment Variables - Naomi/Hikari/discord_token" +FORUM_API_KEY="op://Environment Variables - Naomi/Hikari/discourse_key" +ANNOUNCEMENT_TOKEN="op://Environment Variables - Naomi/Hikari/announcement_token" \ No newline at end of file diff --git a/server/eslint.config.js b/server/eslint.config.js index abc76e5..7276928 100644 --- a/server/eslint.config.js +++ b/server/eslint.config.js @@ -1,5 +1,18 @@ import NaomisConfig from '@nhcarrigan/eslint-config'; export default [ - ...NaomisConfig + ...NaomisConfig, + { + files: ["src/routes/*.ts"], + rules: { + "max-lines-per-function": "off", + } + }, + { + files: ["src/routes/*.ts"], + rules: { + // We turn this off so we can use the async plugin syntax without needing to await. + "@typescript-eslint/require-await": "off", + } + } ] \ No newline at end of file diff --git a/server/package.json b/server/package.json index 7d8521b..4d9ad95 100644 --- a/server/package.json +++ b/server/package.json @@ -6,6 +6,7 @@ "type": "module", "scripts": { "lint": "eslint ./src --max-warnings 0", + "dev": "NODE_ENV=dev op run --env-file=./dev.env -- tsx watch ./src/index.ts", "build": "tsc", "start": "op run --env-file=./prod.env -- node ./prod/index.js", "test": "echo 'No tests yet' && exit 0" @@ -15,10 +16,14 @@ "license": "ISC", "packageManager": "pnpm@10.12.3", "dependencies": { + "@fastify/cors": "11.0.1", "@nhcarrigan/logger": "1.0.0", + "@prisma/client": "6.11.1", "fastify": "5.4.0" }, "devDependencies": { - "@types/node": "24.0.10" + "@types/node": "24.0.10", + "prisma": "6.11.1", + "tsx": "4.20.3" } } diff --git a/server/prisma/schema.prisma b/server/prisma/schema.prisma new file mode 100644 index 0000000..5044a32 --- /dev/null +++ b/server/prisma/schema.prisma @@ -0,0 +1,19 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "mongodb" + url = env("MONGO_URI") +} + +model Announcements { + id String @id @default(auto()) @map("_id") @db.ObjectId + title String + content String + type String + createdAt DateTime @default(now()) @unique +} \ No newline at end of file diff --git a/server/prod.env b/server/prod.env index 12d0e13..547fe45 100644 --- a/server/prod.env +++ b/server/prod.env @@ -1 +1,5 @@ LOG_TOKEN="op://Environment Variables - Naomi/Alert Server/api_auth" +MONGO_URI="op://Environment Variables - Naomi/Hikari/mongo_uri" +DISCORD_TOKEN="op://Environment Variables - Naomi/Hikari/discord_token" +FORUM_API_KEY="op://Environment Variables - Naomi/Hikari/discourse_key" +ANNOUNCEMENT_TOKEN="op://Environment Variables - Naomi/Hikari/announcement_token" \ No newline at end of file diff --git a/server/src/cache/blockedIps.ts b/server/src/cache/blockedIps.ts new file mode 100644 index 0000000..5277359 --- /dev/null +++ b/server/src/cache/blockedIps.ts @@ -0,0 +1,7 @@ +/** + * @copyright nhcarrigan + * @license Naomi's Public License + * @author Naomi Carrigan + */ + +export const blockedIps: Array<{ ip: string; ttl: Date }> = []; diff --git a/server/src/config/routesWithoutCors.ts b/server/src/config/routesWithoutCors.ts new file mode 100644 index 0000000..e8bdd1b --- /dev/null +++ b/server/src/config/routesWithoutCors.ts @@ -0,0 +1,15 @@ +/** + * @copyright nhcarrigan + * @license Naomi's Public License + * @author Naomi Carrigan + */ + +/** + * If you want a route to allow any origin for CORS, add + * the full path to this array. + */ +export const routesWithoutCors = [ + "/", + "/announcement", + "/health", +]; diff --git a/server/src/db/database.ts b/server/src/db/database.ts new file mode 100644 index 0000000..a8c6b55 --- /dev/null +++ b/server/src/db/database.ts @@ -0,0 +1,24 @@ +/** + * @copyright nhcarrigan + * @license Naomi's Public License + * @author Naomi Carrigan + */ + +import { PrismaClient } from "@prisma/client"; + +class Database { + private readonly instance: PrismaClient; + + public constructor() { + this.instance = new PrismaClient(); + void this.instance.$connect(); + } + + public getInstance(): PrismaClient { + return this.instance; + } +} + +const database = new Database(); + +export { database }; diff --git a/server/src/hooks/cors.ts b/server/src/hooks/cors.ts new file mode 100644 index 0000000..8fc6f39 --- /dev/null +++ b/server/src/hooks/cors.ts @@ -0,0 +1,42 @@ +/** + * @copyright nhcarrigan + * @license Naomi's Public License + * @author Naomi Carrigan + */ + +import { routesWithoutCors } from "../config/routesWithoutCors.js"; +import type { onRequestHookHandler } from "fastify"; + +const isValidOrigin = (origin: string | undefined): boolean => { + if (origin === undefined) { + // We do not allow server-to-server requests. + return false; + } + if (process.env.NODE_ENV === "dev" && origin === "http://localhost:4200") { + // We allow the client to access the server when both are running locally. + return true; + } + // Otherwise, we only allow requests from our web application. + return origin === "https://hikari.nhcarrigan.com"; +}; + +/** + * Ensures that form submissions only come from our web application. + * @param request - The request payload from the server. + * @param response - The reply handler from Fastify. + * @returns A Fastify reply if the request is invalid, otherwise undefined. + */ +// eslint-disable-next-line @typescript-eslint/no-misused-promises -- For reasons I cannot comprehend, Fastify seems to require us to return a request? +export const corsHook: onRequestHookHandler = async(request, response) => { + if (routesWithoutCors.includes(request.url)) { + return undefined; + } + if (!isValidOrigin(request.headers.origin)) { + return await response.status(403).send({ + error: + // eslint-disable-next-line stylistic/max-len -- This is a long error message. + "This route is only accessible from our dashboard at https://hikari.nhcarrigan.com.", + }); + } + return undefined; +}; diff --git a/server/src/hooks/ips.ts b/server/src/hooks/ips.ts new file mode 100644 index 0000000..d892adc --- /dev/null +++ b/server/src/hooks/ips.ts @@ -0,0 +1,36 @@ +/** + * @copyright nhcarrigan + * @license Naomi's Public License + * @author Naomi Carrigan + */ + +import { blockedIps } from "../cache/blockedIps.js"; +import { getIpFromRequest } from "../modules/getIpFromRequest.js"; +import type { onRequestHookHandler } from "fastify"; + +/** + * Ensures that form submissions only come from our web application. + * @param request - The request payload from the server. + * @param response - The reply handler from Fastify. + * @returns A Fastify reply if the request is invalid, otherwise undefined. + */ +// eslint-disable-next-line @typescript-eslint/no-misused-promises -- For reasons I cannot comprehend, Fastify seems to require us to return a request? +export const ipHook: onRequestHookHandler = async(request, response) => { + const ip = getIpFromRequest(request); + const ipRecord = blockedIps.find( + (record) => { + return record.ip === ip && record.ttl > new Date(); + }, + ); + if (ipRecord && ipRecord.ttl > new Date()) { + return await response. + status(403). + send({ + error: `Your IP address (${ipRecord.ip}) has been blocked until ${ipRecord.ttl.toISOString()}, to protect our API against brute-force attacks.`, + }); + } + if (ipRecord && ipRecord.ttl <= new Date()) { + blockedIps.splice(blockedIps.indexOf(ipRecord), 1); + } + return undefined; +}; diff --git a/server/src/index.ts b/server/src/index.ts index c64d8f3..38f38f8 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -4,25 +4,41 @@ * @author Naomi Carrigan */ +import cors from "@fastify/cors"; import fastify from "fastify"; +import { corsHook } from "./hooks/cors.js"; +import { ipHook } from "./hooks/ips.js"; +import { announcementRoutes } from "./routes/announcement.js"; +import { baseRoutes } from "./routes/base.js"; import { logger } from "./utils/logger.js"; const server = fastify({ logger: false, }); -server.get("/", async(_request, reply) => { - reply.redirect("https://hikari.nhcarrigan.com"); +/** + * This needs to be first, to ensure all requests have CORS configured. + * Our CORS settings allow for any origin, because we have a custom hook + * that guards specific routes from CORS requests. + * This is to allow our uptime monitor to access the health check route, for example. + * @see routesWithoutCors.ts + */ +server.register(cors, { + origin: "*", }); -server.get("/health", async(_request, reply) => { - reply.status(200).send("OK~!"); -}); +server.addHook("preHandler", corsHook); +server.addHook("preHandler", ipHook); + +server.register(baseRoutes); +server.register(announcementRoutes); server.listen({ port: 20_000 }, (error) => { if (error) { void logger.error("instantiate server", error); return; } - void logger.log("debug", "Server listening on port 20000."); + if (process.env.NODE_ENV !== "dev") { + void logger.log("debug", "Server listening on port 20000."); + } }); diff --git a/server/src/modules/announceOnDiscord.ts b/server/src/modules/announceOnDiscord.ts new file mode 100644 index 0000000..0f6afa0 --- /dev/null +++ b/server/src/modules/announceOnDiscord.ts @@ -0,0 +1,65 @@ +/** + * @copyright nhcarrigan + * @license Naomi's Public License + * @author Naomi Carrigan + */ +/* eslint-disable @typescript-eslint/naming-convention -- we are making raw API calls. */ + +const channelIds = { + community: "1386105484313886820", + products: "1386105452881776661", +} as const; +const roleIds = { + community: "1386107941224054895", + products: "1386107909699666121", +} as const; + +/** + * Forwards an announcement to our Discord server. + * @param title - The title of the announcement. + * @param content - The main body of the announcement. + * @param type - Whether the announcement is for a product or community. + * @returns A message indicating the success or failure of the operation. + */ +export const announceOnDiscord = async( + title: string, + content: string, + type: "products" | "community", +): Promise => { + const messageRequest = await fetch( + `https://discord.com/api/v10/channels/${channelIds[type]}/messages`, + { + body: JSON.stringify({ + allowed_mentions: { parse: [ "users", "roles" ] }, + content: `# ${title}\n\n${content}\n-# <@&${roleIds[type]}>`, + }), + headers: { + "Authorization": `Bot ${process.env.DISCORD_TOKEN ?? ""}`, + "Content-Type": "application/json", + }, + method: "POST", + }, + ); + if (messageRequest.status !== 200) { + return "Failed to send message to Discord."; + } + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- fetch does not accept generics. + const message = await messageRequest.json() as { id?: string }; + if (message.id === undefined) { + return "Failed to parse message ID, cannot crosspost."; + } + const crosspostRequest = await fetch( + `https://discord.com/api/v10/channels/${channelIds[type]}/messages/${message.id}/crosspost`, + { + headers: { + "Authorization": `Bot ${process.env.DISCORD_TOKEN ?? ""}`, + "Content-Type": "application/json", + }, + method: "POST", + }, + ); + if (!crosspostRequest.ok) { + return "Failed to crosspost message to Discord."; + } + return "Successfully sent and published message to Discord."; +}; diff --git a/server/src/modules/announceOnForum.ts b/server/src/modules/announceOnForum.ts new file mode 100644 index 0000000..a4a5b9a --- /dev/null +++ b/server/src/modules/announceOnForum.ts @@ -0,0 +1,40 @@ +/** + * @copyright nhcarrigan + * @license Naomi's Public License + * @author Naomi Carrigan + */ +/* eslint-disable @typescript-eslint/naming-convention -- we are making raw API calls. */ +/** + * Forwards an announcement to our Discord server. + * @param title - The title of the announcement. + * @param content - The main body of the announcement. + * @param type - Whether the announcement is for a product or community. + * @returns A message indicating the success or failure of the operation. + */ +export const announceOnForum = async( + title: string, + content: string, + type: "products" | "community", +): Promise => { + const forumRequest = await fetch( + `https://forum.nhcarrigan.com/posts.json`, + { + body: JSON.stringify({ + category: 14, + raw: content, + tags: [ type ], + title: title, + }), + headers: { + "Api-Key": process.env.FORUM_API_KEY ?? "", + "Api-Username": "Hikari", + "Content-Type": "application/json", + }, + method: "POST", + }, + ); + if (forumRequest.status !== 200) { + return "Failed to send message to forum."; + } + return "Successfully sent message to forum."; +}; diff --git a/server/src/modules/getIpFromRequest.ts b/server/src/modules/getIpFromRequest.ts new file mode 100644 index 0000000..5050dfe --- /dev/null +++ b/server/src/modules/getIpFromRequest.ts @@ -0,0 +1,25 @@ +/** + * @copyright nhcarrigan + * @license Naomi's Public License + * @author Naomi Carrigan + */ + +import type { FastifyRequest } from "fastify"; + +/** + * Parses an IP address from a request, first looking for the + * Cloudflare headers, then falling back to the request IP. + * @param request - The Fastify request object. + * @returns The IP address as a string. + */ +export const getIpFromRequest = (request: FastifyRequest): string => { + const header + = request.headers["X-Forwarded-For"] ?? request.headers["Cf-Connecting-IP"]; + if (typeof header === "string") { + return header; + } + if (Array.isArray(header)) { + return header[0] ?? header.join(", "); + } + return request.ip; +}; diff --git a/server/src/routes/announcement.ts b/server/src/routes/announcement.ts new file mode 100644 index 0000000..9b71efe --- /dev/null +++ b/server/src/routes/announcement.ts @@ -0,0 +1,110 @@ +/** + * @copyright nhcarrigan + * @license Naomi's Public License + * @author Naomi Carrigan + */ + +import { blockedIps } from "../cache/blockedIps.js"; +import { database } from "../db/database.js"; +import { announceOnDiscord } from "../modules/announceOnDiscord.js"; +import { announceOnForum } from "../modules/announceOnForum.js"; +import { getIpFromRequest } from "../modules/getIpFromRequest.js"; +import type { FastifyPluginAsync } from "fastify"; + +const oneDay = 24 * 60 * 60 * 1000; + +/** + * Mounts the entry routes for the application. These routes + * should not require CORS, as they are used by external services + * such as our uptime monitor. + * @param server - The Fastify server instance. + */ +export const announcementRoutes: FastifyPluginAsync = async(server) => { + server.get("/announcements", async(_request, reply) => { + const announcements = await database.getInstance().announcements.findMany({ + orderBy: { + createdAt: "desc", + }, + take: 10, + }); + return await reply.status(200).type("application/json"). + send(announcements.map((announcement) => { + return { + content: announcement.content, + createdAt: announcement.createdAt, + title: announcement.title, + type: announcement.type, + }; + })); + }); + + // eslint-disable-next-line @typescript-eslint/naming-convention -- Fastify requires Body instead of body. + server.post<{ Body: { title: string; content: string; type: string } }>( + "/announcement", + // eslint-disable-next-line complexity -- This is a complex route, but it is necessary to validate the announcement. + async(request, reply) => { + const token = request.headers.authorization; + if (token === undefined || token !== process.env.ANNOUNCEMENT_TOKEN) { + blockedIps.push({ + ip: getIpFromRequest(request), + ttl: new Date(Date.now() + oneDay), + }); + return await reply.status(401).send({ + error: + // eslint-disable-next-line stylistic/max-len -- Big boi string. + "This endpoint requires a special auth token. If you believe you should have access, please contact Naomi. To protect our services, your IP has been blocked from all routes for 24 hours.", + }); + } + + const { title, content, type } = request.body; + if ( + typeof title !== "string" + || typeof content !== "string" + || typeof type !== "string" + || title.length === 0 + || content.length === 0 + || type.length === 0 + ) { + return await reply.status(400).send({ + error: "Missing required fields.", + }); + } + + if (title.length < 20) { + return await reply.status(400).send({ + error: + // eslint-disable-next-line stylistic/max-len -- Big boi string. + "Title must be at least 20 characters long so that it may be posted on our forum.", + }); + } + + if (content.length < 50) { + return await reply.status(400).send({ + error: + // eslint-disable-next-line stylistic/max-len -- Big boi string. + "Content must be at least 50 characters long so that it may be posted on our forum.", + }); + } + + if (type !== "products" && type !== "community") { + return await reply.status(400).send({ + error: "Invalid announcement type.", + }); + } + + await database.getInstance().announcements.create({ + data: { + content, + title, + type, + }, + }); + + const discord = await announceOnDiscord(title, content, type); + const forum = await announceOnForum(title, content, type); + return await reply.status(201).send({ + message: `Announcement processed. Discord: ${discord}, Forum: ${forum}`, + }); + }, + ); +}; diff --git a/server/src/routes/base.ts b/server/src/routes/base.ts new file mode 100644 index 0000000..43efe75 --- /dev/null +++ b/server/src/routes/base.ts @@ -0,0 +1,23 @@ +/** + * @copyright nhcarrigan + * @license Naomi's Public License + * @author Naomi Carrigan + */ + +import type { FastifyPluginAsync } from "fastify"; + +/** + * Mounts the entry routes for the application. These routes + * should not require CORS, as they are used by external services + * such as our uptime monitor. + * @param server - The Fastify server instance. + */ +export const baseRoutes: FastifyPluginAsync = async(server) => { + server.get("/", async(_request, reply) => { + return await reply.redirect("https://hikari.nhcarrigan.com"); + }); + + server.get("/health", async(_request, reply) => { + return await reply.status(200).send("OK~!"); + }); +};