diff --git a/.vscode/settings.json b/.vscode/settings.json index a6ffc5d..0425ac9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,6 +8,15 @@ "source.organizeImports.biome": "explicit", "source.fixAll.biome": "explicit" }, + "files.readonlyInclude": { + "**/routeTree.gen.ts": true + }, + "files.watcherExclude": { + "**/routeTree.gen.ts": true + }, + "search.exclude": { + "**/routeTree.gen.ts": true + }, "files.exclude": { "**/.git": true, "**/.svn": true, @@ -15,5 +24,5 @@ "**/CVS": true, "**/.DS_Store": true, "**/Thumbs.db": true - }, + } } diff --git a/api/package.json b/api/package.json index 177ef02..71ca7a0 100644 --- a/api/package.json +++ b/api/package.json @@ -6,6 +6,6 @@ "dependencies": { "@module/payment": "workspace:*", "@platform/config": "workspace:*", - "zod": "4.1.13" + "zod": "4.3.5" } } diff --git a/app/package.json b/app/package.json index 0d36bf0..daa00a6 100644 --- a/app/package.json +++ b/app/package.json @@ -34,7 +34,7 @@ "@tailwindcss/vite": "4.1.17", "@tanstack/react-router": "1.139.9", "@tanstack/react-table": "8.21.3", - "@valkyr/db": "npm:@jsr/valkyr__db@2.0.0", + "@valkyr/db": "npm:@jsr/valkyr__db@3.0.1", "@zitadel/react": "1.1.0", "class-variance-authority": "0.7.1", "clsx": "2.1.1", @@ -48,10 +48,12 @@ "tailwind-merge": "3.4.0", "tailwindcss": "4.1.17", "vaul": "1.1.2", - "zod": "4.1.13" + "zod": "4.3.5" }, "devDependencies": { "@eslint/js": "9.39.1", + "@tanstack/react-router-devtools": "1.144.0", + "@tanstack/router-plugin": "1.145.2", "@types/node": "24.10.1", "@types/react": "19.2.7", "@types/react-dom": "19.2.3", diff --git a/app/src/app/auth/callback.view.tsx b/app/src/app/auth/callback.view.tsx deleted file mode 100644 index 2f1bec9..0000000 --- a/app/src/app/auth/callback.view.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { useNavigate } from "@tanstack/react-router"; -import { useEffect } from "react"; - -import { zitadel } from "../../services/zitadel.ts"; - -export function CallbackView() { - const navigate = useNavigate(); - useEffect(() => { - async function handleCallback() { - try { - const user = await zitadel.userManager.signinRedirectCallback(); - if (user) { - navigate({ to: "/", replace: true }); - } else { - navigate({ to: "/", replace: true }); - } - } catch (error) { - console.error("Callback error", error); - navigate({ to: "/", replace: true }); - } - } - handleCallback(); - }, [navigate]); - - return null; -} diff --git a/app/src/app/auth/components/login-form.tsx b/app/src/app/auth/components/login-form.tsx deleted file mode 100644 index 200d9ce..0000000 --- a/app/src/app/auth/components/login-form.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { GalleryVerticalEnd } from "lucide-react"; - -import { Button } from "@/components/ui/button"; -import { Field, FieldDescription, FieldGroup, FieldSeparator } from "@/components/ui/field"; -import { cn } from "@/lib/utils"; -import { zitadel } from "@/services/zitadel.ts"; - -export function LoginForm({ className, ...props }: React.ComponentProps<"div">) { - return ( -
-
{ - e.preventDefault(); - zitadel.authorize(); - }} - > - -
- -
- -
- Valkyr Sandbox -
-

Welcome to Valkyr Sandbox

- - Don't have an account? Sign up - -
- - - - Or - - - - -
-
- - By clicking continue, you agree to our Terms of Service and Privacy Policy. - -
- ); -} diff --git a/app/src/app/auth/login.view.tsx b/app/src/app/auth/login.view.tsx deleted file mode 100644 index a9d9508..0000000 --- a/app/src/app/auth/login.view.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { LoginForm } from "./components/login-form.tsx"; - -export function LoginView() { - return ( -
-
- -
-
- ); -} diff --git a/app/src/app/dashboard/dashboard.controller.ts b/app/src/app/dashboard/dashboard.controller.ts deleted file mode 100644 index 9175f8e..0000000 --- a/app/src/app/dashboard/dashboard.controller.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { Controller } from "@/lib/controller.tsx"; - -export class DashboardController extends Controller {} diff --git a/app/src/app/dashboard/dashboard.view.tsx b/app/src/app/dashboard/dashboard.view.tsx deleted file mode 100644 index f5507a9..0000000 --- a/app/src/app/dashboard/dashboard.view.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { makeControllerComponent } from "@/lib/controller.tsx"; - -import { DashboardController } from "./dashboard.controller.ts"; - -export const DashboardView = makeControllerComponent(DashboardController, () => { - return
Dashboard
; -}); diff --git a/app/src/components/app-sidebar.controller.ts b/app/src/components/app-sidebar.controller.ts index ba82086..e716938 100644 --- a/app/src/components/app-sidebar.controller.ts +++ b/app/src/components/app-sidebar.controller.ts @@ -1,7 +1,7 @@ import { GalleryVerticalEnd } from "lucide-react"; import { Controller } from "@/lib/controller.tsx"; -import { User } from "@/services/user.ts"; +import { auth } from "@/services/auth.ts"; type Tenant = { name: string; @@ -13,7 +13,7 @@ export class AppSiderbarController extends Controller<{ tenant: Tenant; }> { async onInit() { - const user = await User.resolve(); + const user = auth.user; if (user === undefined) { return { tenant: { diff --git a/app/src/components/payment/create-beneficiary.tsx b/app/src/components/beneficiary/create.component.tsx similarity index 62% rename from app/src/components/payment/create-beneficiary.tsx rename to app/src/components/beneficiary/create.component.tsx index 3015786..1d55e3c 100644 --- a/app/src/components/payment/create-beneficiary.tsx +++ b/app/src/components/beneficiary/create.component.tsx @@ -12,20 +12,25 @@ import { DialogTrigger, } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; import { LoadingSwap } from "@/components/ui/loading-swap"; import { SidebarMenuSubButton } from "@/components/ui/sidebar.tsx"; import { makeControllerComponent } from "../../lib/controller.tsx"; -import { CreateBeneficiaryController } from "./create-beneficiary.controller.ts"; +import { FieldDescription, FieldGroup, FieldLabel } from "../ui/field.tsx"; +import { CreateBeneficiaryController } from "./create.controller.ts"; export const DialogCreateBeneficiary = makeControllerComponent( CreateBeneficiaryController, - ({ title, setLabel, submit, isSubmitting, ...props }) => { + ({ title, label, setLabel, submit, isSubmitting, ...props }) => { const labelId = useId(); return ( -
+ { + e.preventDefault(); + submit(); + }} + > {title} @@ -33,20 +38,25 @@ export const DialogCreateBeneficiary = makeControllerComponent( - Create beneficiary + Create Beneficiary Create a payment ledger and its supported currencies -
-
- - setLabel(value)} /> -
-
+ + Label + setLabel(value)} + required + /> + Enter the identifying label for the Beneficiary + - diff --git a/app/src/components/payment/create-beneficiary.controller.ts b/app/src/components/beneficiary/create.controller.ts similarity index 75% rename from app/src/components/payment/create-beneficiary.controller.ts rename to app/src/components/beneficiary/create.controller.ts index 20486bb..32ff1a7 100644 --- a/app/src/components/payment/create-beneficiary.controller.ts +++ b/app/src/components/beneficiary/create.controller.ts @@ -3,32 +3,32 @@ import type { LucideIcon } from "lucide-react"; import { payment } from "@/database/payment.ts"; import { Controller } from "@/lib/controller.tsx"; import { api, getSuccessResponse } from "@/services/api.ts"; -import { User } from "@/services/user.ts"; +import { auth } from "@/services/auth.ts"; export class CreateBeneficiaryController extends Controller< { isSubmitting: boolean; + label: string; }, { title: string; icon: LucideIcon } > { - #label?: string; - async onInit() { return { isSubmitting: false, + label: "", }; } setLabel(label: string) { - this.#label = label; + this.setState("label", label); } async submit() { this.setState("isSubmitting", true); const res = await api.payment.benficiaries.create({ body: { - tenantId: await User.getTenantId(), - label: this.#label, + tenantId: auth.user.tenant.id, + label: this.state.label, }, }); if ("data" in res) { @@ -36,6 +36,9 @@ export class CreateBeneficiaryController extends Controller< .collection("beneficiary") .insertOne(await getSuccessResponse(api.payment.benficiaries.id({ params: { id: res.data } }))); } - this.setState("isSubmitting", false); + this.setState({ + isSubmitting: false, + label: "", + }); } } diff --git a/app/src/components/beneficiary/read.component.tsx b/app/src/components/beneficiary/read.component.tsx new file mode 100644 index 0000000..0ce9529 --- /dev/null +++ b/app/src/components/beneficiary/read.component.tsx @@ -0,0 +1,15 @@ +import { makeControllerComponent } from "@/lib/controller.tsx"; + +import { ReadBeneficiaryController } from "./read.controller.ts"; + +export const BeneficiaryComponent = makeControllerComponent(ReadBeneficiaryController, ({ beneficiary }) => { + if (beneficiary === undefined) { + return ( +
+

Beneficiary Not Found

+

Beneficiary with id "xxx" cannot be found.

+
+ ); + } + return
{JSON.stringify(beneficiary, null, 2)}
; +}); diff --git a/app/src/components/beneficiary/read.controller.ts b/app/src/components/beneficiary/read.controller.ts new file mode 100644 index 0000000..0bcaa7e --- /dev/null +++ b/app/src/components/beneficiary/read.controller.ts @@ -0,0 +1,37 @@ +import type { Beneficiary } from "@module/payment/client"; + +import { payment } from "@/database/payment.ts"; +import { Controller } from "@/lib/controller.tsx"; +import { auth } from "@/services/auth.ts"; + +export class ReadBeneficiaryController extends Controller< + { + beneficiary?: Beneficiary; + }, + { + id: string; + } +> { + #subscription?: any; + + async onInit() { + await this.#subscribe(this.props.id); + } + + async onResolve() { + await this.#subscribe(this.props.id); + } + + async onDestroy(): Promise { + this.#subscription?.unsubscribe(); + } + + async #subscribe(_id: string) { + this.#subscription?.unsubscribe(); + this.#subscription = await payment + .collection("beneficiary") + .subscribe({ _id, tenantId: auth.user.tenant.id }, { limit: 1 }, (beneficiary) => { + this.setState("beneficiary", beneficiary); + }); + } +} diff --git a/app/src/components/nav-payment.controller.ts b/app/src/components/nav-payment.controller.ts index a8cb04e..9b4d5df 100644 --- a/app/src/components/nav-payment.controller.ts +++ b/app/src/components/nav-payment.controller.ts @@ -2,11 +2,10 @@ import type { Beneficiary } from "@module/payment/client"; import { Book, CirclePlusIcon, type LucideIcon, SquareTerminal } from "lucide-react"; import type { FunctionComponent } from "react"; +import { DialogCreateBeneficiary } from "@/components/beneficiary/create.component.tsx"; import { loadBeneficiaries, payment } from "@/database/payment.ts"; import { Controller } from "@/lib/controller.tsx"; -import { User } from "@/services/user.ts"; - -import { DialogCreateBeneficiary } from "./payment/create-beneficiary.tsx"; +import { auth } from "@/services/auth.ts"; export class NavPaymentController extends Controller<{ items: MenuItem[]; @@ -19,7 +18,7 @@ export class NavPaymentController extends Controller<{ items: [ { title: "Dashboard", - url: "/payment", + url: "/", icon: SquareTerminal, }, ], @@ -31,7 +30,7 @@ export class NavPaymentController extends Controller<{ this.#subscriptions.push( await payment .collection("beneficiary") - .subscribe({ tenantId: await User.getTenantId() }, { sort: { label: 1 } }, (beneficiaries) => { + .subscribe({ tenantId: auth.user.tenant.id }, { sort: { label: 1 } }, (beneficiaries) => { this.setState("items", this.#getMenuItems(beneficiaries)); }), ); @@ -41,7 +40,7 @@ export class NavPaymentController extends Controller<{ return [ { title: "Dashboard", - url: "/payment", + url: "/", icon: SquareTerminal, }, { @@ -57,7 +56,7 @@ export class NavPaymentController extends Controller<{ }, ...beneficiaries.map((beneficiary) => ({ title: beneficiary.label ?? "Unlabeled", - url: `/payment/${beneficiary._id}`, + url: `/beneficiaries/${beneficiary._id}`, })), ], }, diff --git a/app/src/components/ui/field.tsx b/app/src/components/ui/field.tsx index 1303b9b..85f4620 100644 --- a/app/src/components/ui/field.tsx +++ b/app/src/components/ui/field.tsx @@ -39,7 +39,7 @@ function FieldGroup({ className, ...props }: React.ComponentProps<"div">) {
[data-slot=field-group]]:gap-4", + "group/field-group @container/field-group flex w-full flex-col gap-3 data-[slot=checkbox-group]:gap-3 [&>[data-slot=field-group]]:gap-4", className, )} {...props} diff --git a/app/src/app/payment/dashboard/dashboard.controller.ts b/app/src/controllers/dashboard.controller.ts similarity index 78% rename from app/src/app/payment/dashboard/dashboard.controller.ts rename to app/src/controllers/dashboard.controller.ts index 2aece52..a230936 100644 --- a/app/src/app/payment/dashboard/dashboard.controller.ts +++ b/app/src/controllers/dashboard.controller.ts @@ -2,9 +2,9 @@ import type { Beneficiary } from "@module/payment/client"; import { loadBeneficiaries, payment } from "@/database/payment.ts"; import { Controller } from "@/lib/controller.tsx"; -import { User } from "@/services/user.ts"; +import { auth } from "@/services/auth.ts"; -export class PaymentDashboardController extends Controller<{ +export class DashboardController extends Controller<{ beneficiaries: Beneficiary[]; }> { #subscriptions: any[] = []; @@ -28,7 +28,7 @@ export class PaymentDashboardController extends Controller<{ this.#subscriptions.push( await payment .collection("beneficiary") - .subscribe({ tenantId: await User.getTenantId() }, { sort: { label: 1 } }, (documents) => { + .subscribe({ tenantId: auth.user.tenant.id }, { sort: { label: 1 } }, (documents) => { this.setState("beneficiaries", documents); }), ); diff --git a/app/src/database/payment.ts b/app/src/database/payment.ts index 31fd37c..a633f75 100644 --- a/app/src/database/payment.ts +++ b/app/src/database/payment.ts @@ -1,43 +1,89 @@ -import type { Account, Beneficiary, Ledger, Transaction, Wallet } from "@module/payment/client"; -import { IndexedDatabase } from "@valkyr/db"; +import { + AccountSchema, + BeneficiarySchema, + LedgerSchema, + TransactionSchema, + WalletSchema, +} from "@module/payment/client"; +import { IndexedDB } from "@valkyr/db"; import { api } from "@/services/api.ts"; -export const payment = new IndexedDatabase<{ - account: Account; - beneficiary: Beneficiary; - ledger: Ledger; - transaction: Transaction; - wallet: Wallet; -}>({ +export const payment = new IndexedDB({ name: "valkyr-sandbox:payment", registrars: [ { name: "account", - indexes: [["_id", { unique: true }], ["walletId"]], + schema: AccountSchema.shape, + indexes: [ + { + field: "_id", + kind: "primary", + }, + { + field: "walletId", + kind: "shared", + }, + ], }, { name: "beneficiary", - indexes: [["_id", { unique: true }], ["tenantId"]], + schema: BeneficiarySchema.shape, + indexes: [ + { + field: "_id", + kind: "primary", + }, + { + field: "tenantId", + kind: "shared", + }, + ], }, { name: "ledger", - indexes: [["_id", { unique: true }], ["beneficiaryId"]], + schema: LedgerSchema.shape, + indexes: [ + { + field: "_id", + kind: "primary", + }, + { + field: "beneficiaryId", + kind: "shared", + }, + ], }, { name: "transaction", - indexes: [["_id", { unique: true }]], + schema: TransactionSchema.shape, + indexes: [ + { + field: "_id", + kind: "primary", + }, + ], }, { name: "wallet", - indexes: [["_id", { unique: true }], ["ledgerId"]], + schema: WalletSchema.shape, + indexes: [ + { + field: "_id", + kind: "primary", + }, + { + field: "ledgerId", + kind: "shared", + }, + ], }, - ], + ] as const, }); export async function loadBeneficiaries(): Promise { const result = await api.payment.benficiaries.list(); if ("data" in result) { - payment.collection("beneficiary").insertMany(result.data); + payment.collection("beneficiary").insert(result.data); } } diff --git a/app/src/lib/controller.tsx b/app/src/lib/controller.tsx index 473feab..21761c7 100644 --- a/app/src/lib/controller.tsx +++ b/app/src/lib/controller.tsx @@ -50,7 +50,7 @@ export abstract class Controller< return; } const state = await this.onInit(); - if (this.#destroyed === false) { + if (this.#destroyed === false && state !== undefined) { this.setState(state); } this.#initiated = true; @@ -64,10 +64,7 @@ export abstract class Controller< if (this.onResolve === undefined) { return; } - const state: Partial = await this.onResolve(); - if (this.#destroyed === false) { - this.setState({ ...this.state, ...state }); - } + await this.onResolve(); } async $destroy(): Promise { @@ -84,16 +81,12 @@ export abstract class Controller< /** * Called every time props change (including first mount). */ - async onInit(): Promise> { - return {}; - } + async onInit(): Promise | void> {} /** * Called every time props change (including first mount). */ - async onResolve(): Promise> { - return {}; - } + async onResolve(): Promise {} /** * Called when the controller is destroyed. diff --git a/app/src/lib/router.ts b/app/src/lib/router.ts new file mode 100644 index 0000000..985e612 --- /dev/null +++ b/app/src/lib/router.ts @@ -0,0 +1,28 @@ +import { createRouter } from "@tanstack/react-router"; + +import { auth } from "@/services/auth.ts"; + +import { routeTree } from "../routeTree.gen.ts"; + +export const router = createRouter({ + routeTree, + defaultPreload: "intent", + scrollRestoration: true, + context: { + auth, + }, +}); + +export function getRouteParam(key: string): string { + return getRouteParams()[key] ?? ""; +} + +export function getRouteParams(): Record { + return router.state.matches.at(-1)?.params ?? {}; +} + +declare module "@tanstack/react-router" { + interface Register { + router: typeof router; + } +} diff --git a/app/src/lib/router.tsx b/app/src/lib/router.tsx deleted file mode 100644 index f745a95..0000000 --- a/app/src/lib/router.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { createRootRoute, createRoute, createRouter, redirect } from "@tanstack/react-router"; - -import { AppView } from "@/app/app.view.tsx"; -import { CallbackView } from "@/app/auth/callback.view.tsx"; -import { LoginView } from "@/app/auth/login.view.tsx"; -import { DashboardView } from "@/app/dashboard/dashboard.view.tsx"; -import { zitadel } from "@/services/zitadel.ts"; - -import { PaymentDashboardView } from "../app/payment/dashboard/dashboard.view.tsx"; - -const root = createRootRoute(); - -const callback = createRoute({ - getParentRoute: () => root, - path: "/auth/callback", - component: CallbackView, -}); - -const login = createRoute({ - getParentRoute: () => root, - path: "/login", - component: LoginView, -}); - -const app = createRoute({ - id: "app", - getParentRoute: () => root, - beforeLoad: async () => { - const user = await zitadel.userManager.getUser(); - if (user === null) { - throw redirect({ to: "/login" }); - } - if (user.expired === true) { - throw redirect({ to: "/login" }); - } - }, - component: AppView, -}); - -const dashboard = createRoute({ - getParentRoute: () => app, - path: "/", - component: DashboardView, -}); - -const payment = [ - createRoute({ - getParentRoute: () => app, - path: "/payment", - component: PaymentDashboardView, - }), -]; - -root.addChildren([app, login, callback]); -app.addChildren([dashboard, ...payment]); - -export const router = createRouter({ routeTree: root }); diff --git a/app/src/main.tsx b/app/src/main.tsx index e486d57..b004f9a 100644 --- a/app/src/main.tsx +++ b/app/src/main.tsx @@ -3,14 +3,9 @@ import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import { ThemeProvider } from "@/components/theme-provider.tsx"; -import { router } from "@/lib/router.tsx"; -import "./index.css"; +import { router } from "@/lib/router"; -declare module "@tanstack/react-router" { - interface Register { - router: typeof router; - } -} +import "./index.css"; const rootElement = document.getElementById("root"); if (rootElement === null) { diff --git a/app/src/routeTree.gen.ts b/app/src/routeTree.gen.ts new file mode 100644 index 0000000..39ae543 --- /dev/null +++ b/app/src/routeTree.gen.ts @@ -0,0 +1,126 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import { Route as rootRouteImport } from './routes/__root' +import { Route as CallbackRouteImport } from './routes/callback' +import { Route as AuthRouteRouteImport } from './routes/_auth/route' +import { Route as AuthIndexRouteImport } from './routes/_auth/index' +import { Route as AuthBeneficiariesBeneficiaryIdRouteImport } from './routes/_auth/beneficiaries/$beneficiaryId' + +const CallbackRoute = CallbackRouteImport.update({ + id: '/callback', + path: '/callback', + getParentRoute: () => rootRouteImport, +} as any) +const AuthRouteRoute = AuthRouteRouteImport.update({ + id: '/_auth', + getParentRoute: () => rootRouteImport, +} as any) +const AuthIndexRoute = AuthIndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => AuthRouteRoute, +} as any) +const AuthBeneficiariesBeneficiaryIdRoute = + AuthBeneficiariesBeneficiaryIdRouteImport.update({ + id: '/beneficiaries/$beneficiaryId', + path: '/beneficiaries/$beneficiaryId', + getParentRoute: () => AuthRouteRoute, + } as any) + +export interface FileRoutesByFullPath { + '/callback': typeof CallbackRoute + '/': typeof AuthIndexRoute + '/beneficiaries/$beneficiaryId': typeof AuthBeneficiariesBeneficiaryIdRoute +} +export interface FileRoutesByTo { + '/callback': typeof CallbackRoute + '/': typeof AuthIndexRoute + '/beneficiaries/$beneficiaryId': typeof AuthBeneficiariesBeneficiaryIdRoute +} +export interface FileRoutesById { + __root__: typeof rootRouteImport + '/_auth': typeof AuthRouteRouteWithChildren + '/callback': typeof CallbackRoute + '/_auth/': typeof AuthIndexRoute + '/_auth/beneficiaries/$beneficiaryId': typeof AuthBeneficiariesBeneficiaryIdRoute +} +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: '/callback' | '/' | '/beneficiaries/$beneficiaryId' + fileRoutesByTo: FileRoutesByTo + to: '/callback' | '/' | '/beneficiaries/$beneficiaryId' + id: + | '__root__' + | '/_auth' + | '/callback' + | '/_auth/' + | '/_auth/beneficiaries/$beneficiaryId' + fileRoutesById: FileRoutesById +} +export interface RootRouteChildren { + AuthRouteRoute: typeof AuthRouteRouteWithChildren + CallbackRoute: typeof CallbackRoute +} + +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/callback': { + id: '/callback' + path: '/callback' + fullPath: '/callback' + preLoaderRoute: typeof CallbackRouteImport + parentRoute: typeof rootRouteImport + } + '/_auth': { + id: '/_auth' + path: '' + fullPath: '' + preLoaderRoute: typeof AuthRouteRouteImport + parentRoute: typeof rootRouteImport + } + '/_auth/': { + id: '/_auth/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof AuthIndexRouteImport + parentRoute: typeof AuthRouteRoute + } + '/_auth/beneficiaries/$beneficiaryId': { + id: '/_auth/beneficiaries/$beneficiaryId' + path: '/beneficiaries/$beneficiaryId' + fullPath: '/beneficiaries/$beneficiaryId' + preLoaderRoute: typeof AuthBeneficiariesBeneficiaryIdRouteImport + parentRoute: typeof AuthRouteRoute + } + } +} + +interface AuthRouteRouteChildren { + AuthIndexRoute: typeof AuthIndexRoute + AuthBeneficiariesBeneficiaryIdRoute: typeof AuthBeneficiariesBeneficiaryIdRoute +} + +const AuthRouteRouteChildren: AuthRouteRouteChildren = { + AuthIndexRoute: AuthIndexRoute, + AuthBeneficiariesBeneficiaryIdRoute: AuthBeneficiariesBeneficiaryIdRoute, +} + +const AuthRouteRouteWithChildren = AuthRouteRoute._addFileChildren( + AuthRouteRouteChildren, +) + +const rootRouteChildren: RootRouteChildren = { + AuthRouteRoute: AuthRouteRouteWithChildren, + CallbackRoute: CallbackRoute, +} +export const routeTree = rootRouteImport + ._addFileChildren(rootRouteChildren) + ._addFileTypes() diff --git a/app/src/routes/__root.tsx b/app/src/routes/__root.tsx new file mode 100644 index 0000000..d9ce3f7 --- /dev/null +++ b/app/src/routes/__root.tsx @@ -0,0 +1,19 @@ +import { createRootRouteWithContext, Outlet } from "@tanstack/react-router"; +import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; + +import type { AuthContext } from "@/services/auth.ts"; + +export const Route = createRootRouteWithContext<{ + auth: AuthContext; +}>()({ + component: RootComponent, +}); + +function RootComponent() { + return ( + <> + + + + ); +} diff --git a/app/src/routes/_auth/beneficiaries/$beneficiaryId.tsx b/app/src/routes/_auth/beneficiaries/$beneficiaryId.tsx new file mode 100644 index 0000000..d962423 --- /dev/null +++ b/app/src/routes/_auth/beneficiaries/$beneficiaryId.tsx @@ -0,0 +1,12 @@ +import { createFileRoute } from "@tanstack/react-router"; + +import { BeneficiaryComponent } from "@/components/beneficiary/read.component.tsx"; + +export const Route = createFileRoute("/_auth/beneficiaries/$beneficiaryId")({ + component: BeneficiaryRoute, +}); + +function BeneficiaryRoute() { + const { beneficiaryId } = Route.useParams(); + return ; +} diff --git a/app/src/app/payment/dashboard/dashboard.view.tsx b/app/src/routes/_auth/index.tsx similarity index 65% rename from app/src/app/payment/dashboard/dashboard.view.tsx rename to app/src/routes/_auth/index.tsx index 2ad3c7f..ddd0f95 100644 --- a/app/src/app/payment/dashboard/dashboard.view.tsx +++ b/app/src/routes/_auth/index.tsx @@ -1,8 +1,9 @@ +import { createFileRoute } from "@tanstack/react-router"; + +import { DashboardController } from "@/controllers/dashboard.controller.ts"; import { makeControllerComponent } from "@/lib/controller.tsx"; -import { PaymentDashboardController } from "./dashboard.controller.ts"; - -export const PaymentDashboardView = makeControllerComponent(PaymentDashboardController, ({ beneficiaries }) => { +const DashboardComponent = makeControllerComponent(DashboardController, ({ beneficiaries }) => { if (beneficiaries.length === 0) { return (
@@ -20,3 +21,7 @@ export const PaymentDashboardView = makeControllerComponent(PaymentDashboardCont
); }); + +export const Route = createFileRoute("/_auth/")({ + component: DashboardComponent, +}); diff --git a/app/src/app/app.view.tsx b/app/src/routes/_auth/route.tsx similarity index 71% rename from app/src/app/app.view.tsx rename to app/src/routes/_auth/route.tsx index 1103c0e..99de18f 100644 --- a/app/src/app/app.view.tsx +++ b/app/src/routes/_auth/route.tsx @@ -1,10 +1,20 @@ -import { Outlet } from "@tanstack/react-router"; +import { createFileRoute, Outlet } from "@tanstack/react-router"; import { AppSidebar } from "@/components/app-sidebar"; import { SiteHeader } from "@/components/site-header"; import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar"; -export function AppView() { +export const Route = createFileRoute("/_auth")({ + beforeLoad: async ({ context: { auth } }) => { + await auth.resolve(); + if (auth.isAuthenticated === false) { + throw auth.login(); + } + }, + component: AppLayout, +}); + +function AppLayout() { return ( { + zitadel.userManager + .signinRedirectCallback() + .then(() => { + navigate({ to: "/", replace: true }); + }) + .catch((error) => { + console.error("Callback error", error); + setError(error); + }); + }, [navigate]); + + if (error) { + return
Error!
; + } + + return null; +} diff --git a/app/src/services/auth.ts b/app/src/services/auth.ts new file mode 100644 index 0000000..d62da8f --- /dev/null +++ b/app/src/services/auth.ts @@ -0,0 +1,32 @@ +import { User } from "@/services/user.ts"; +import { zitadel } from "@/services/zitadel.ts"; + +export const auth: AuthContext = { + get isAuthenticated() { + return User.isAuthenticated; + }, + + get user() { + return User.instance; + }, + + async resolve() { + await User.resolve(); + }, + + async login() { + await zitadel.authorize(); + }, + + async logout() { + await zitadel.signout(); + }, +}; + +export type AuthContext = { + isAuthenticated: boolean; + user: User; + resolve: () => Promise; + login: () => Promise; + logout: () => Promise; +}; diff --git a/app/src/services/user.ts b/app/src/services/user.ts index cfc67a5..c748885 100644 --- a/app/src/services/user.ts +++ b/app/src/services/user.ts @@ -1,4 +1,3 @@ -import { redirect } from "@tanstack/react-router"; import z from "zod"; import { type ZitadelUser, zitadel } from "./zitadel.ts"; @@ -35,20 +34,23 @@ export class User { this.tenant = tenant; } - static async getTenantId() { - return User.get().then((user) => user.tenant.id); + static get isAuthenticated() { + return cached !== undefined; } - static async getTenantName() { - return User.get().then((user) => user.tenant.name); - } - - static async get() { - const user = await User.resolve(); - if (user === undefined) { - throw redirect({ to: "/login" }); + static get instance() { + if (cached === undefined) { + throw zitadel.authorize(); } - return user; + return cached; + } + + static get tenantId() { + return User.instance.tenant.id; + } + + static get tenantName() { + return User.instance.tenant.name; } static async resolve() { diff --git a/app/src/services/zitadel.ts b/app/src/services/zitadel.ts index feb505e..07b14b6 100644 --- a/app/src/services/zitadel.ts +++ b/app/src/services/zitadel.ts @@ -4,7 +4,7 @@ const config: ZitadelConfig = { authority: "https://iam.valkyrjs.com", project_resource_id: "348389288439709700", client_id: "348389308220112900", - redirect_uri: "http://localhost:5173/auth/callback", + redirect_uri: "http://localhost:5173/callback", post_logout_redirect_uri: "http://localhost:5173", response_type: "code", scope: "openid profile email urn:zitadel:iam:user:metadata urn:zitadel:iam:org:id:348388915649970180", diff --git a/app/vite.config.ts b/app/vite.config.ts index 46ff00c..1e36a8a 100644 --- a/app/vite.config.ts +++ b/app/vite.config.ts @@ -1,12 +1,20 @@ import path from "node:path"; import tailwindcss from "@tailwindcss/vite"; +import { tanstackRouter } from "@tanstack/router-plugin/vite"; import react from "@vitejs/plugin-react"; import { defineConfig } from "vite"; // https://vite.dev/config/ export default defineConfig({ - plugins: [react(), tailwindcss()], + plugins: [ + tailwindcss(), + tanstackRouter({ + target: "react", + autoCodeSplitting: true, + }), + react(), + ], resolve: { alias: { "@": path.resolve(__dirname, "./src"), diff --git a/apps/react/package.json b/apps/react/package.json index 6f90324..c9904fb 100644 --- a/apps/react/package.json +++ b/apps/react/package.json @@ -37,7 +37,7 @@ "tailwindcss": "4.1.13", "tailwindcss-animate": "^1.0.7", "tw-animate-css": "1.4.0", - "zod": "4.1.13" + "zod": "4.3.5" }, "devDependencies": { "@eslint/js": "9.35.0", diff --git a/biome.json b/biome.json index e01dce7..032ccfd 100644 --- a/biome.json +++ b/biome.json @@ -1,4 +1,5 @@ { + "$schema": "https://biomejs.dev/schemas/2.2.4/schema.json", "formatter": { "enabled": true, "formatWithErrors": false, @@ -42,4 +43,4 @@ } } } -} \ No newline at end of file +} diff --git a/deno.lock b/deno.lock index c9861bd..629c493 100644 --- a/deno.lock +++ b/deno.lock @@ -2,8 +2,8 @@ "version": "5", "specifiers": { "npm:@biomejs/biome@2.2.4": "2.2.4", - "npm:@cerbos/core@0.25.1": "0.25.1_@bufbuild+protobuf@2.10.1", - "npm:@cerbos/http@0.23.3": "0.23.3_@bufbuild+protobuf@2.10.1_@cerbos+api@0.2.0", + "npm:@cerbos/core@0.25.1": "0.25.1_@bufbuild+protobuf@2.10.2", + "npm:@cerbos/http@0.23.3": "0.23.3_@bufbuild+protobuf@2.10.2_@cerbos+api@0.2.0", "npm:@dnd-kit/core@6.3.1": "6.3.1_react@19.2.0_react-dom@19.2.0__react@19.2.0", "npm:@dnd-kit/modifiers@9.0.0": "9.0.0_@dnd-kit+core@6.3.1__react@19.2.0__react-dom@19.2.0___react@19.2.0_react@19.2.0_react-dom@19.2.0__react@19.2.0", "npm:@dnd-kit/sortable@10.0.0": "10.0.0_@dnd-kit+core@6.3.1__react@19.2.0__react-dom@19.2.0___react@19.2.0_react@19.2.0_react-dom@19.2.0__react@19.2.0", @@ -12,7 +12,7 @@ "npm:@jsr/std__assert@1.0.14": "1.0.14", "npm:@jsr/std__dotenv@0.225.5": "0.225.5", "npm:@jsr/std__testing@1.0.15": "1.0.15", - "npm:@jsr/valkyr__db@2.0.0": "2.0.0", + "npm:@jsr/valkyr__db@3.0.1": "3.0.1", "npm:@jsr/valkyr__event-store@2.0.1": "2.0.1", "npm:@jsr/valkyr__json-rpc@1.1.0": "1.1.0", "npm:@radix-ui/react-avatar@1.1.11": "1.1.11_@types+react@19.2.7_@types+react-dom@19.2.3__@types+react@19.2.7_react@19.2.0_react-dom@19.2.0__react@19.2.0", @@ -31,8 +31,10 @@ "npm:@radix-ui/react-tooltip@1.2.8": "1.2.8_@types+react@19.2.7_@types+react-dom@19.2.3__@types+react@19.2.7_react@19.2.0_react-dom@19.2.0__react@19.2.0", "npm:@tabler/icons-react@3.35.0": "3.35.0_react@19.2.0", "npm:@tailwindcss/vite@4.1.17": "4.1.17_vite@7.2.4__@types+node@24.10.1__picomatch@4.0.3_@types+node@24.10.1", + "npm:@tanstack/react-router-devtools@1.144.0": "1.144.0_@tanstack+react-router@1.139.9__react@19.2.0__react-dom@19.2.0___react@19.2.0_react@19.2.0_react-dom@19.2.0__react@19.2.0", "npm:@tanstack/react-router@1.139.9": "1.139.9_react@19.2.0_react-dom@19.2.0__react@19.2.0", "npm:@tanstack/react-table@8.21.3": "8.21.3_react@19.2.0_react-dom@19.2.0__react@19.2.0", + "npm:@tanstack/router-plugin@1.145.2": "1.145.2_@tanstack+react-router@1.139.9__react@19.2.0__react-dom@19.2.0___react@19.2.0_vite@7.2.4__@types+node@24.10.1__picomatch@4.0.3_@babel+core@7.28.5_react@19.2.0_react-dom@19.2.0__react@19.2.0_@types+node@24.10.1", "npm:@types/node@24.10.1": "24.10.1", "npm:@types/react-dom@19.2.3": "19.2.3_@types+react@19.2.7", "npm:@types/react@19.2.7": "19.2.7", @@ -43,7 +45,7 @@ "npm:class-variance-authority@0.7.1": "0.7.1", "npm:clsx@2.1.1": "2.1.1", "npm:cmdk@^1.1.1": "1.1.1_react@19.2.0_react-dom@19.2.0__react@19.2.0_@types+react@19.2.7_@types+react-dom@19.2.3__@types+react@19.2.7", - "npm:eslint-plugin-react-hooks@7.0.1": "7.0.1_eslint@9.39.1_zod@4.1.13", + "npm:eslint-plugin-react-hooks@7.0.1": "7.0.1_eslint@9.39.1_zod@4.3.5", "npm:eslint-plugin-react-refresh@0.4.24": "0.4.24_eslint@9.39.1", "npm:eslint@9.39.1": "9.39.1", "npm:globals@16.5.0": "16.5.0", @@ -65,7 +67,7 @@ "npm:typescript@~5.9.3": "5.9.3", "npm:vaul@1.1.2": "1.1.2_react@19.2.0_react-dom@19.2.0__react@19.2.0_@types+react@19.2.7_@types+react-dom@19.2.3__@types+react@19.2.7", "npm:vite@7.2.4": "7.2.4_@types+node@24.10.1_picomatch@4.0.3", - "npm:zod@4.1.13": "4.1.13" + "npm:zod@4.3.5": "4.3.5" }, "npm": { "@babel/code-frame@7.27.1": { @@ -164,6 +166,20 @@ ], "bin": true }, + "@babel/plugin-syntax-jsx@7.27.1_@babel+core@7.28.5": { + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "dependencies": [ + "@babel/core", + "@babel/helper-plugin-utils" + ] + }, + "@babel/plugin-syntax-typescript@7.27.1_@babel+core@7.28.5": { + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "dependencies": [ + "@babel/core", + "@babel/helper-plugin-utils" + ] + }, "@babel/plugin-transform-react-jsx-self@7.27.1_@babel+core@7.28.5": { "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", "dependencies": [ @@ -262,8 +278,8 @@ "os": ["win32"], "cpu": ["x64"] }, - "@bufbuild/protobuf@2.10.1": { - "integrity": "sha512-ckS3+vyJb5qGpEYv/s1OebUHDi/xSNtfgw1wqKZo7MR9F2z+qXr0q5XagafAG/9O0QPVIUfST0smluYSTpYFkg==" + "@bufbuild/protobuf@2.10.2": { + "integrity": "sha512-uFsRXwIGyu+r6AMdz+XijIIZJYpoWeYzILt5yZ2d3mCjQrWUTVpVD9WL/jZAbvp+Ed04rOhrsk7FiTcEDseB5A==" }, "@cerbos/api@0.2.0": { "integrity": "sha512-p3kAfmgz0WwxXBJ8Dt1vugV/QjQoPtF5b1R+h16YnUPZ6O4YL8D9gjz5WQRg/0FllodyaEtJlrMPxGEvJetkIw==", @@ -271,7 +287,7 @@ "@bufbuild/protobuf" ] }, - "@cerbos/core@0.25.1_@bufbuild+protobuf@2.10.1": { + "@cerbos/core@0.25.1_@bufbuild+protobuf@2.10.2": { "integrity": "sha512-aPi8IqqgGHq9xyoBk6dYAKQ1U1athW0YZfI+7lzxxwpLlNFdZ9EwJLhaRSUFgYpUS2TBWDtX094Yn1kgB1esCQ==", "dependencies": [ "@bufbuild/protobuf", @@ -279,7 +295,7 @@ "uuid" ] }, - "@cerbos/http@0.23.3_@bufbuild+protobuf@2.10.1_@cerbos+api@0.2.0": { + "@cerbos/http@0.23.3_@bufbuild+protobuf@2.10.2_@cerbos+api@0.2.0": { "integrity": "sha512-yf8s4v+T4sf/ZiLorHpXhdStOr+q5XEjF2m/yvpcR7E/7e5eGCr5yEov9NIgfRQg1HGW8h+B6CIFBl9amSsaGw==", "dependencies": [ "@bufbuild/protobuf", @@ -335,133 +351,263 @@ "os": ["aix"], "cpu": ["ppc64"] }, + "@esbuild/aix-ppc64@0.27.2": { + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "os": ["aix"], + "cpu": ["ppc64"] + }, "@esbuild/android-arm64@0.25.12": { "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", "os": ["android"], "cpu": ["arm64"] }, + "@esbuild/android-arm64@0.27.2": { + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "os": ["android"], + "cpu": ["arm64"] + }, "@esbuild/android-arm@0.25.12": { "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", "os": ["android"], "cpu": ["arm"] }, + "@esbuild/android-arm@0.27.2": { + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "os": ["android"], + "cpu": ["arm"] + }, "@esbuild/android-x64@0.25.12": { "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", "os": ["android"], "cpu": ["x64"] }, + "@esbuild/android-x64@0.27.2": { + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "os": ["android"], + "cpu": ["x64"] + }, "@esbuild/darwin-arm64@0.25.12": { "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", "os": ["darwin"], "cpu": ["arm64"] }, + "@esbuild/darwin-arm64@0.27.2": { + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "os": ["darwin"], + "cpu": ["arm64"] + }, "@esbuild/darwin-x64@0.25.12": { "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", "os": ["darwin"], "cpu": ["x64"] }, + "@esbuild/darwin-x64@0.27.2": { + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "os": ["darwin"], + "cpu": ["x64"] + }, "@esbuild/freebsd-arm64@0.25.12": { "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", "os": ["freebsd"], "cpu": ["arm64"] }, + "@esbuild/freebsd-arm64@0.27.2": { + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "os": ["freebsd"], + "cpu": ["arm64"] + }, "@esbuild/freebsd-x64@0.25.12": { "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", "os": ["freebsd"], "cpu": ["x64"] }, + "@esbuild/freebsd-x64@0.27.2": { + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "os": ["freebsd"], + "cpu": ["x64"] + }, "@esbuild/linux-arm64@0.25.12": { "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", "os": ["linux"], "cpu": ["arm64"] }, + "@esbuild/linux-arm64@0.27.2": { + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "os": ["linux"], + "cpu": ["arm64"] + }, "@esbuild/linux-arm@0.25.12": { "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", "os": ["linux"], "cpu": ["arm"] }, + "@esbuild/linux-arm@0.27.2": { + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "os": ["linux"], + "cpu": ["arm"] + }, "@esbuild/linux-ia32@0.25.12": { "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", "os": ["linux"], "cpu": ["ia32"] }, + "@esbuild/linux-ia32@0.27.2": { + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "os": ["linux"], + "cpu": ["ia32"] + }, "@esbuild/linux-loong64@0.25.12": { "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", "os": ["linux"], "cpu": ["loong64"] }, + "@esbuild/linux-loong64@0.27.2": { + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "os": ["linux"], + "cpu": ["loong64"] + }, "@esbuild/linux-mips64el@0.25.12": { "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", "os": ["linux"], "cpu": ["mips64el"] }, + "@esbuild/linux-mips64el@0.27.2": { + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "os": ["linux"], + "cpu": ["mips64el"] + }, "@esbuild/linux-ppc64@0.25.12": { "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", "os": ["linux"], "cpu": ["ppc64"] }, + "@esbuild/linux-ppc64@0.27.2": { + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "os": ["linux"], + "cpu": ["ppc64"] + }, "@esbuild/linux-riscv64@0.25.12": { "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", "os": ["linux"], "cpu": ["riscv64"] }, + "@esbuild/linux-riscv64@0.27.2": { + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "os": ["linux"], + "cpu": ["riscv64"] + }, "@esbuild/linux-s390x@0.25.12": { "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", "os": ["linux"], "cpu": ["s390x"] }, + "@esbuild/linux-s390x@0.27.2": { + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "os": ["linux"], + "cpu": ["s390x"] + }, "@esbuild/linux-x64@0.25.12": { "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", "os": ["linux"], "cpu": ["x64"] }, + "@esbuild/linux-x64@0.27.2": { + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "os": ["linux"], + "cpu": ["x64"] + }, "@esbuild/netbsd-arm64@0.25.12": { "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", "os": ["netbsd"], "cpu": ["arm64"] }, + "@esbuild/netbsd-arm64@0.27.2": { + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "os": ["netbsd"], + "cpu": ["arm64"] + }, "@esbuild/netbsd-x64@0.25.12": { "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", "os": ["netbsd"], "cpu": ["x64"] }, + "@esbuild/netbsd-x64@0.27.2": { + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "os": ["netbsd"], + "cpu": ["x64"] + }, "@esbuild/openbsd-arm64@0.25.12": { "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", "os": ["openbsd"], "cpu": ["arm64"] }, + "@esbuild/openbsd-arm64@0.27.2": { + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "os": ["openbsd"], + "cpu": ["arm64"] + }, "@esbuild/openbsd-x64@0.25.12": { "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", "os": ["openbsd"], "cpu": ["x64"] }, + "@esbuild/openbsd-x64@0.27.2": { + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "os": ["openbsd"], + "cpu": ["x64"] + }, "@esbuild/openharmony-arm64@0.25.12": { "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", "os": ["openharmony"], "cpu": ["arm64"] }, + "@esbuild/openharmony-arm64@0.27.2": { + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "os": ["openharmony"], + "cpu": ["arm64"] + }, "@esbuild/sunos-x64@0.25.12": { "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", "os": ["sunos"], "cpu": ["x64"] }, + "@esbuild/sunos-x64@0.27.2": { + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "os": ["sunos"], + "cpu": ["x64"] + }, "@esbuild/win32-arm64@0.25.12": { "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", "os": ["win32"], "cpu": ["arm64"] }, + "@esbuild/win32-arm64@0.27.2": { + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "os": ["win32"], + "cpu": ["arm64"] + }, "@esbuild/win32-ia32@0.25.12": { "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", "os": ["win32"], "cpu": ["ia32"] }, + "@esbuild/win32-ia32@0.27.2": { + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "os": ["win32"], + "cpu": ["ia32"] + }, "@esbuild/win32-x64@0.25.12": { "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", "os": ["win32"], "cpu": ["x64"] }, - "@eslint-community/eslint-utils@4.9.0_eslint@9.39.1": { - "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "@esbuild/win32-x64@0.27.2": { + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "os": ["win32"], + "cpu": ["x64"] + }, + "@eslint-community/eslint-utils@4.9.1_eslint@9.39.1": { + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "dependencies": [ "eslint", "eslint-visitor-keys@3.4.3" @@ -490,8 +636,8 @@ "@types/json-schema" ] }, - "@eslint/eslintrc@3.3.1": { - "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "@eslint/eslintrc@3.3.3": { + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", "dependencies": [ "ajv", "debug", @@ -591,9 +737,9 @@ ], "tarball": "https://npm.jsr.io/~/11/@jsr/std__assert/1.0.14.tgz" }, - "@jsr/std__async@1.0.15": { - "integrity": "sha512-GW6tMWwF79kKKVths4SWcju1cFykhcE+jiV6/k2IOW45611ji+Yomm0MZuW7JR4Oug+GXF0POrsAiSqL8k/9PQ==", - "tarball": "https://npm.jsr.io/~/11/@jsr/std__async/1.0.15.tgz" + "@jsr/std__async@1.0.16": { + "integrity": "sha512-WoYmNEPSh+Bs09HvVceERknVX813wQjSb2D9Z0KdxGTMYl5Pm13e5xqa3mYu9QBRlxIxpTivGhIQYaslEezrhw==", + "tarball": "https://npm.jsr.io/~/11/@jsr/std__async/1.0.16.tgz" }, "@jsr/std__data-structures@1.0.9": { "integrity": "sha512-+mT4Nll6fx+CPNqrlC+huhIOYNSMS+KUdJ4B8NujiQrh/bq++ds5PXpEsfV5EPR+YuWcuDGG0P1DE+Rednd7Wg==", @@ -606,13 +752,13 @@ "integrity": "sha512-qrBt3wfQgvXbjo+Up6lyzBGxk0IPhDqW9Jx7CJQUQpsxqhoqnBmD8gn0Mt8i+RHHI9uZFCO+FP122ClAC8yljg==", "tarball": "https://npm.jsr.io/~/11/@jsr/std__dotenv/0.225.5.tgz" }, - "@jsr/std__fs@1.0.20": { - "integrity": "sha512-wBw/Y+EfWVgZq6qlqD8M84q0kSuPwLmjnXy97KGfdrkorvzTZCs5AbHElsed/Yi90PuH39tvNhLCHeRGObUwPA==", + "@jsr/std__fs@1.0.21": { + "integrity": "sha512-k/agrcKGm6KD89ci3AEyRmu3wRWf9JZNliOF4ZUxagTHiySmxjiKU3Lk+d2ksRtwEi7oWlLGS0AVM9Lciwc/xg==", "dependencies": [ "@jsr/std__internal", "@jsr/std__path" ], - "tarball": "https://npm.jsr.io/~/11/@jsr/std__fs/1.0.20.tgz" + "tarball": "https://npm.jsr.io/~/11/@jsr/std__fs/1.0.21.tgz" }, "@jsr/std__internal@1.0.12": { "integrity": "sha512-6xReMW9p+paJgqoFRpOE2nogJFvzPfaLHLIlyADYjKMUcwDyjKZxryIbgcU+gxiTygn8yCjld1HoI0ET4/iZeA==", @@ -622,12 +768,12 @@ "integrity": "sha512-mh27Fw4UMCjGSIMoOhjia5cS5fNP9M9DZYhGB7EYSZNnzf/eguFiarii/W4oDwYMmnxCMouUzhc6Y7jFuwTzcg==", "tarball": "https://npm.jsr.io/~/11/@jsr/std__net/1.0.6.tgz" }, - "@jsr/std__path@1.1.3": { - "integrity": "sha512-7HAc3nOGizbIunNCUQ4mrF7XY/SpAEIlq5pBR0sOzkcLB7520baEqnOmXTFiIUTp/umKE5ArEegMM1F39N51Rg==", + "@jsr/std__path@1.1.4": { + "integrity": "sha512-SK4u9H6NVTfolhPdlvdYXfNFefy1W04AEHWJydryYbk+xqzNiVmr5o7TLJLJFqwHXuwMRhwrn+mcYeUfS0YFaA==", "dependencies": [ "@jsr/std__internal" ], - "tarball": "https://npm.jsr.io/~/11/@jsr/std__path/1.1.3.tgz" + "tarball": "https://npm.jsr.io/~/11/@jsr/std__path/1.1.4.tgz" }, "@jsr/std__testing@1.0.15": { "integrity": "sha512-NgQuXxTEG4ecbh2fzYbkJWJoBgPXwbv6bdsrAYSOeLpX2d+TROEzpErbWQXHi/yxZy/FNn9IF548ZDAqMZxi/g==", @@ -646,11 +792,21 @@ "dependencies": [ "bson", "idb", - "mingo", + "mingo@6.7.2", "rxjs" ], "tarball": "https://npm.jsr.io/~/11/@jsr/valkyr__db/2.0.0.tgz" }, + "@jsr/valkyr__db@3.0.1": { + "integrity": "sha512-fOSiEMELURwPbOhJ8qyNLiINETmNHOZV+46m4sNDTBv6nojhts53taStIAjYDTioQH0T7KdXCOEnS2bHwOilhA==", + "dependencies": [ + "@jsr/valkyr__event-emitter", + "idb", + "mingo@7.1.1", + "zod@4.3.4" + ], + "tarball": "https://npm.jsr.io/~/11/@jsr/valkyr__db/3.0.1.tgz" + }, "@jsr/valkyr__event-emitter@1.0.1": { "integrity": "sha512-mre5tWJddz8LylSQWuLOw3zgIxd2JmhGRV46jKXNPCGzY2NKJwGGT9H7SBw36RV4dW7jnnH2U1aCJkh8IS/pzA==", "dependencies": [ @@ -661,11 +817,11 @@ "@jsr/valkyr__event-store@2.0.1": { "integrity": "sha512-OvSPX0XH5+oS4zQh1O8J7JvsCoH5pBFNuJ1PdNA5B0OascrSWUqpxNEmytOtJhZuhfYzdvyOU1yNEvSI84D5wg==", "dependencies": [ - "@jsr/valkyr__db", + "@jsr/valkyr__db@2.0.0", "@jsr/valkyr__testcontainers", "mongodb", "postgres", - "zod" + "zod@4.3.5" ], "tarball": "https://npm.jsr.io/~/11/@jsr/valkyr__event-store/2.0.1.tgz" }, @@ -687,8 +843,8 @@ ], "tarball": "https://npm.jsr.io/~/11/@jsr/valkyr__testcontainers/2.0.2.tgz" }, - "@mongodb-js/saslprep@1.3.2": { - "integrity": "sha512-QgA5AySqB27cGTXBFmnpifAi7HxoGUeezwo6p9dI03MuDB6Pp33zgclqVb6oVK3j6I9Vesg0+oojW2XxB59SGg==", + "@mongodb-js/saslprep@1.4.4": { + "integrity": "sha512-p7X/ytJDIdwUfFL/CLOhKgdfJe1Fa8uw9seJYvdOmnP9JBWGWHW69HkOixXS6Wy9yvGf1MbhcS6lVmrhy4jm2g==", "dependencies": [ "sparse-bitfield" ] @@ -1394,113 +1550,128 @@ "@rolldown/pluginutils@1.0.0-beta.47": { "integrity": "sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw==" }, - "@rollup/rollup-android-arm-eabi@4.53.3": { - "integrity": "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==", + "@rollup/rollup-android-arm-eabi@4.55.1": { + "integrity": "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==", "os": ["android"], "cpu": ["arm"] }, - "@rollup/rollup-android-arm64@4.53.3": { - "integrity": "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==", + "@rollup/rollup-android-arm64@4.55.1": { + "integrity": "sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==", "os": ["android"], "cpu": ["arm64"] }, - "@rollup/rollup-darwin-arm64@4.53.3": { - "integrity": "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==", + "@rollup/rollup-darwin-arm64@4.55.1": { + "integrity": "sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==", "os": ["darwin"], "cpu": ["arm64"] }, - "@rollup/rollup-darwin-x64@4.53.3": { - "integrity": "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==", + "@rollup/rollup-darwin-x64@4.55.1": { + "integrity": "sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==", "os": ["darwin"], "cpu": ["x64"] }, - "@rollup/rollup-freebsd-arm64@4.53.3": { - "integrity": "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==", + "@rollup/rollup-freebsd-arm64@4.55.1": { + "integrity": "sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==", "os": ["freebsd"], "cpu": ["arm64"] }, - "@rollup/rollup-freebsd-x64@4.53.3": { - "integrity": "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==", + "@rollup/rollup-freebsd-x64@4.55.1": { + "integrity": "sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==", "os": ["freebsd"], "cpu": ["x64"] }, - "@rollup/rollup-linux-arm-gnueabihf@4.53.3": { - "integrity": "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==", + "@rollup/rollup-linux-arm-gnueabihf@4.55.1": { + "integrity": "sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==", "os": ["linux"], "cpu": ["arm"] }, - "@rollup/rollup-linux-arm-musleabihf@4.53.3": { - "integrity": "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==", + "@rollup/rollup-linux-arm-musleabihf@4.55.1": { + "integrity": "sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==", "os": ["linux"], "cpu": ["arm"] }, - "@rollup/rollup-linux-arm64-gnu@4.53.3": { - "integrity": "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==", + "@rollup/rollup-linux-arm64-gnu@4.55.1": { + "integrity": "sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==", "os": ["linux"], "cpu": ["arm64"] }, - "@rollup/rollup-linux-arm64-musl@4.53.3": { - "integrity": "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==", + "@rollup/rollup-linux-arm64-musl@4.55.1": { + "integrity": "sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==", "os": ["linux"], "cpu": ["arm64"] }, - "@rollup/rollup-linux-loong64-gnu@4.53.3": { - "integrity": "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==", + "@rollup/rollup-linux-loong64-gnu@4.55.1": { + "integrity": "sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==", "os": ["linux"], "cpu": ["loong64"] }, - "@rollup/rollup-linux-ppc64-gnu@4.53.3": { - "integrity": "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==", + "@rollup/rollup-linux-loong64-musl@4.55.1": { + "integrity": "sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==", + "os": ["linux"], + "cpu": ["loong64"] + }, + "@rollup/rollup-linux-ppc64-gnu@4.55.1": { + "integrity": "sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==", "os": ["linux"], "cpu": ["ppc64"] }, - "@rollup/rollup-linux-riscv64-gnu@4.53.3": { - "integrity": "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==", + "@rollup/rollup-linux-ppc64-musl@4.55.1": { + "integrity": "sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==", + "os": ["linux"], + "cpu": ["ppc64"] + }, + "@rollup/rollup-linux-riscv64-gnu@4.55.1": { + "integrity": "sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==", "os": ["linux"], "cpu": ["riscv64"] }, - "@rollup/rollup-linux-riscv64-musl@4.53.3": { - "integrity": "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==", + "@rollup/rollup-linux-riscv64-musl@4.55.1": { + "integrity": "sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==", "os": ["linux"], "cpu": ["riscv64"] }, - "@rollup/rollup-linux-s390x-gnu@4.53.3": { - "integrity": "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==", + "@rollup/rollup-linux-s390x-gnu@4.55.1": { + "integrity": "sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==", "os": ["linux"], "cpu": ["s390x"] }, - "@rollup/rollup-linux-x64-gnu@4.53.3": { - "integrity": "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==", + "@rollup/rollup-linux-x64-gnu@4.55.1": { + "integrity": "sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==", "os": ["linux"], "cpu": ["x64"] }, - "@rollup/rollup-linux-x64-musl@4.53.3": { - "integrity": "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==", + "@rollup/rollup-linux-x64-musl@4.55.1": { + "integrity": "sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==", "os": ["linux"], "cpu": ["x64"] }, - "@rollup/rollup-openharmony-arm64@4.53.3": { - "integrity": "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==", + "@rollup/rollup-openbsd-x64@4.55.1": { + "integrity": "sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==", + "os": ["openbsd"], + "cpu": ["x64"] + }, + "@rollup/rollup-openharmony-arm64@4.55.1": { + "integrity": "sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==", "os": ["openharmony"], "cpu": ["arm64"] }, - "@rollup/rollup-win32-arm64-msvc@4.53.3": { - "integrity": "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==", + "@rollup/rollup-win32-arm64-msvc@4.55.1": { + "integrity": "sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==", "os": ["win32"], "cpu": ["arm64"] }, - "@rollup/rollup-win32-ia32-msvc@4.53.3": { - "integrity": "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==", + "@rollup/rollup-win32-ia32-msvc@4.55.1": { + "integrity": "sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==", "os": ["win32"], "cpu": ["ia32"] }, - "@rollup/rollup-win32-x64-gnu@4.53.3": { - "integrity": "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==", + "@rollup/rollup-win32-x64-gnu@4.55.1": { + "integrity": "sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==", "os": ["win32"], "cpu": ["x64"] }, - "@rollup/rollup-win32-x64-msvc@4.53.3": { - "integrity": "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==", + "@rollup/rollup-win32-x64-msvc@4.55.1": { + "integrity": "sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==", "os": ["win32"], "cpu": ["x64"] }, @@ -1614,12 +1785,24 @@ "@tanstack/history@1.139.0": { "integrity": "sha512-l6wcxwDBeh/7Dhles23U1O8lp9kNJmAb2yNjekR6olZwCRNAVA8TCXlVCrueELyFlYZqvQkh0ofxnzG62A1Kkg==" }, + "@tanstack/history@1.141.0": { + "integrity": "sha512-LS54XNyxyTs5m/pl1lkwlg7uZM3lvsv2FIIV1rsJgnfwVCnI+n4ZGZ2CcjNT13BPu/3hPP+iHmliBSscJxW5FQ==" + }, + "@tanstack/react-router-devtools@1.144.0_@tanstack+react-router@1.139.9__react@19.2.0__react-dom@19.2.0___react@19.2.0_react@19.2.0_react-dom@19.2.0__react@19.2.0": { + "integrity": "sha512-nstjZvZbOM4U0/Hzi82rtsP1DsR2tfigBidK+WuaDRVVstBsnwVor3DQXTGY5CcfgIiMI3eKzI17VOy3SQDDoQ==", + "dependencies": [ + "@tanstack/react-router", + "@tanstack/router-devtools-core", + "react", + "react-dom" + ] + }, "@tanstack/react-router@1.139.9_react@19.2.0_react-dom@19.2.0__react@19.2.0": { "integrity": "sha512-1MArdWwbovsAt/zB7ziswpAyLgNLTEmBmjqjQYdjr9ubIVOtt9Z+Lo38wcA1SFNE0o1y0fLmiRCETPB2Afchwg==", "dependencies": [ - "@tanstack/history", + "@tanstack/history@1.139.0", "@tanstack/react-store", - "@tanstack/router-core", + "@tanstack/router-core@1.139.7_seroval@1.4.2", "isbot", "react", "react-dom", @@ -1644,24 +1827,99 @@ "react-dom" ] }, - "@tanstack/router-core@1.139.7_seroval@1.4.0": { + "@tanstack/router-core@1.139.7_seroval@1.4.2": { "integrity": "sha512-mqgsJi4/B2Jo6PXRUs1AsWA+06nqiqVZe1aXioA3vR6PesNeKUSXWfmIoYF6wOx3osiV0BnwB1JCBrInCOQSWA==", "dependencies": [ - "@tanstack/history", + "@tanstack/history@1.139.0", "@tanstack/store", "cookie-es", - "seroval", - "seroval-plugins", + "seroval@1.4.2", + "seroval-plugins@1.4.2_seroval@1.4.2", "tiny-invariant", "tiny-warning" ] }, + "@tanstack/router-core@1.144.0_seroval@1.4.2": { + "integrity": "sha512-6oVERtK9XDHCP4XojgHsdHO56ZSj11YaWjF5g/zw39LhyA6Lx+/X86AEIHO4y0BUrMQaJfcjdAQMVSAs6Vjtdg==", + "dependencies": [ + "@tanstack/history@1.141.0", + "@tanstack/store", + "cookie-es", + "seroval@1.4.2", + "seroval-plugins@1.4.2_seroval@1.4.2", + "tiny-invariant", + "tiny-warning" + ] + }, + "@tanstack/router-devtools-core@1.144.0_@tanstack+router-core@1.144.0__seroval@1.4.2_solid-js@1.9.10__seroval@1.3.2": { + "integrity": "sha512-rbpQn1aHUtcfY3U3SyJqOZRqDu0a2uPK+TE2CH50HieJApmCuNKj5RsjVQYHgwiFFvR0w0LUmueTnl2X2hiWTg==", + "dependencies": [ + "@tanstack/router-core@1.144.0_seroval@1.4.2", + "clsx", + "goober", + "solid-js", + "tiny-invariant" + ] + }, + "@tanstack/router-generator@1.145.2": { + "integrity": "sha512-6DLwfqhexgxw2T2QuS9Y349Vb49hCXBIz9mjWyynjMrpejLXJL+PaHaKJw0Y+H7Ao6RE2vlvXCc2cMjgbz5c7Q==", + "dependencies": [ + "@tanstack/router-core@1.144.0_seroval@1.4.2", + "@tanstack/router-utils", + "@tanstack/virtual-file-routes", + "prettier", + "recast", + "source-map@0.7.6", + "tsx", + "zod@3.25.76" + ] + }, + "@tanstack/router-plugin@1.145.2_@tanstack+react-router@1.139.9__react@19.2.0__react-dom@19.2.0___react@19.2.0_vite@7.2.4__@types+node@24.10.1__picomatch@4.0.3_@babel+core@7.28.5_react@19.2.0_react-dom@19.2.0__react@19.2.0_@types+node@24.10.1": { + "integrity": "sha512-dOABjCE4M2KxB+f/mY71dDZduwVTpf+tCPb4NxmAqbF5Rxes24QaaIZQmiU12jte/L8zYyIA/yX9fi93xZue5Q==", + "dependencies": [ + "@babel/core", + "@babel/plugin-syntax-jsx", + "@babel/plugin-syntax-typescript", + "@babel/template", + "@babel/traverse", + "@babel/types", + "@tanstack/react-router", + "@tanstack/router-core@1.144.0_seroval@1.4.2", + "@tanstack/router-generator", + "@tanstack/router-utils", + "@tanstack/virtual-file-routes", + "babel-dead-code-elimination", + "chokidar", + "unplugin", + "vite", + "zod@3.25.76" + ], + "optionalPeers": [ + "@tanstack/react-router", + "vite" + ] + }, + "@tanstack/router-utils@1.143.11": { + "integrity": "sha512-N24G4LpfyK8dOlnP8BvNdkuxg1xQljkyl6PcrdiPSA301pOjatRT1y8wuCCJZKVVD8gkd0MpCZ0VEjRMGILOtA==", + "dependencies": [ + "@babel/core", + "@babel/generator", + "@babel/parser", + "ansis", + "diff", + "pathe", + "tinyglobby" + ] + }, "@tanstack/store@0.8.0": { "integrity": "sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ==" }, "@tanstack/table-core@8.21.3": { "integrity": "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==" }, + "@tanstack/virtual-file-routes@1.141.0": { + "integrity": "sha512-CJrWtr6L9TVzEImm9S7dQINx+xJcYP/aDkIi6gnaWtIgbZs1pnzsE0yJc2noqXZ+yAOqLx3TBGpBEs9tS0P9/A==" + }, "@types/babel__core@7.20.5": { "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dependencies": [ @@ -1906,6 +2164,16 @@ "color-convert" ] }, + "ansis@4.2.0": { + "integrity": "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==" + }, + "anymatch@3.1.3": { + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": [ + "normalize-path", + "picomatch@2.3.1" + ] + }, "argparse@2.0.1": { "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, @@ -1915,6 +2183,21 @@ "tslib" ] }, + "ast-types@0.16.1": { + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "dependencies": [ + "tslib" + ] + }, + "babel-dead-code-elimination@1.0.11": { + "integrity": "sha512-mwq3W3e/pKSI6TG8lXMiDWvEi1VXYlSBlJlB3l+I0bAb5u1RNUl88udos85eOPNK3m5EXK9uO7d2g08pesTySQ==", + "dependencies": [ + "@babel/core", + "@babel/parser", + "@babel/traverse", + "@babel/types" + ] + }, "babel-plugin-react-compiler@1.0.0": { "integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==", "dependencies": [ @@ -1924,10 +2207,13 @@ "balanced-match@1.0.2": { "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, - "baseline-browser-mapping@2.8.31": { - "integrity": "sha512-a28v2eWrrRWPpJSzxc+mKwm0ZtVx/G8SepdQZDArnXYU/XS+IF6mp8aB/4E+hH1tyGCoDo3KlUCdlSxGDsRkAw==", + "baseline-browser-mapping@2.9.11": { + "integrity": "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==", "bin": true }, + "binary-extensions@2.3.0": { + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==" + }, "brace-expansion@1.1.12": { "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dependencies": [ @@ -1947,8 +2233,8 @@ "fill-range" ] }, - "browserslist@4.28.0": { - "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==", + "browserslist@4.28.1": { + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "dependencies": [ "baseline-browser-mapping", "caniuse-lite", @@ -1978,8 +2264,8 @@ "callsites@3.1.0": { "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" }, - "caniuse-lite@1.0.30001757": { - "integrity": "sha512-r0nnL/I28Zi/yjk1el6ilj27tKcdjLsNqAOZr0yVjWPrSQyHgKI2INaEWw21bAQSv2LXRt1XuCS/GomNpWOxsQ==" + "caniuse-lite@1.0.30001762": { + "integrity": "sha512-PxZwGNvH7Ak8WX5iXzoK1KPZttBXNPuaOvI2ZYU7NrlM+d9Ov+TUvlLOBNGzVXAntMSMMlJPd+jY6ovrVjSmUw==" }, "chalk@4.1.2": { "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -1988,6 +2274,21 @@ "supports-color" ] }, + "chokidar@3.6.0": { + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dependencies": [ + "anymatch", + "braces", + "glob-parent@5.1.2", + "is-binary-path", + "is-glob", + "normalize-path", + "readdirp" + ], + "optionalDependencies": [ + "fsevents" + ] + }, "class-variance-authority@0.7.1": { "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", "dependencies": [ @@ -2113,6 +2414,9 @@ "detect-node-es@1.1.0": { "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" }, + "diff@8.0.2": { + "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==" + }, "dom-helpers@5.2.1": { "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", "dependencies": [ @@ -2128,11 +2432,11 @@ "gopd" ] }, - "electron-to-chromium@1.5.262": { - "integrity": "sha512-NlAsMteRHek05jRUxUR0a5jpjYq9ykk6+kO0yRaMi5moe7u0fVIOeQ3Y30A8dIiWFBNUoQGi1ljb1i5VtS9WQQ==" + "electron-to-chromium@1.5.267": { + "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==" }, - "enhanced-resolve@5.18.3": { - "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "enhanced-resolve@5.18.4": { + "integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==", "dependencies": [ "graceful-fs", "tapable" @@ -2153,32 +2457,65 @@ "esbuild@0.25.12": { "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", "optionalDependencies": [ - "@esbuild/aix-ppc64", - "@esbuild/android-arm", - "@esbuild/android-arm64", - "@esbuild/android-x64", - "@esbuild/darwin-arm64", - "@esbuild/darwin-x64", - "@esbuild/freebsd-arm64", - "@esbuild/freebsd-x64", - "@esbuild/linux-arm", - "@esbuild/linux-arm64", - "@esbuild/linux-ia32", - "@esbuild/linux-loong64", - "@esbuild/linux-mips64el", - "@esbuild/linux-ppc64", - "@esbuild/linux-riscv64", - "@esbuild/linux-s390x", - "@esbuild/linux-x64", - "@esbuild/netbsd-arm64", - "@esbuild/netbsd-x64", - "@esbuild/openbsd-arm64", - "@esbuild/openbsd-x64", - "@esbuild/openharmony-arm64", - "@esbuild/sunos-x64", - "@esbuild/win32-arm64", - "@esbuild/win32-ia32", - "@esbuild/win32-x64" + "@esbuild/aix-ppc64@0.25.12", + "@esbuild/android-arm@0.25.12", + "@esbuild/android-arm64@0.25.12", + "@esbuild/android-x64@0.25.12", + "@esbuild/darwin-arm64@0.25.12", + "@esbuild/darwin-x64@0.25.12", + "@esbuild/freebsd-arm64@0.25.12", + "@esbuild/freebsd-x64@0.25.12", + "@esbuild/linux-arm@0.25.12", + "@esbuild/linux-arm64@0.25.12", + "@esbuild/linux-ia32@0.25.12", + "@esbuild/linux-loong64@0.25.12", + "@esbuild/linux-mips64el@0.25.12", + "@esbuild/linux-ppc64@0.25.12", + "@esbuild/linux-riscv64@0.25.12", + "@esbuild/linux-s390x@0.25.12", + "@esbuild/linux-x64@0.25.12", + "@esbuild/netbsd-arm64@0.25.12", + "@esbuild/netbsd-x64@0.25.12", + "@esbuild/openbsd-arm64@0.25.12", + "@esbuild/openbsd-x64@0.25.12", + "@esbuild/openharmony-arm64@0.25.12", + "@esbuild/sunos-x64@0.25.12", + "@esbuild/win32-arm64@0.25.12", + "@esbuild/win32-ia32@0.25.12", + "@esbuild/win32-x64@0.25.12" + ], + "scripts": true, + "bin": true + }, + "esbuild@0.27.2": { + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "optionalDependencies": [ + "@esbuild/aix-ppc64@0.27.2", + "@esbuild/android-arm@0.27.2", + "@esbuild/android-arm64@0.27.2", + "@esbuild/android-x64@0.27.2", + "@esbuild/darwin-arm64@0.27.2", + "@esbuild/darwin-x64@0.27.2", + "@esbuild/freebsd-arm64@0.27.2", + "@esbuild/freebsd-x64@0.27.2", + "@esbuild/linux-arm@0.27.2", + "@esbuild/linux-arm64@0.27.2", + "@esbuild/linux-ia32@0.27.2", + "@esbuild/linux-loong64@0.27.2", + "@esbuild/linux-mips64el@0.27.2", + "@esbuild/linux-ppc64@0.27.2", + "@esbuild/linux-riscv64@0.27.2", + "@esbuild/linux-s390x@0.27.2", + "@esbuild/linux-x64@0.27.2", + "@esbuild/netbsd-arm64@0.27.2", + "@esbuild/netbsd-x64@0.27.2", + "@esbuild/openbsd-arm64@0.27.2", + "@esbuild/openbsd-x64@0.27.2", + "@esbuild/openharmony-arm64@0.27.2", + "@esbuild/sunos-x64@0.27.2", + "@esbuild/win32-arm64@0.27.2", + "@esbuild/win32-ia32@0.27.2", + "@esbuild/win32-x64@0.27.2" ], "scripts": true, "bin": true @@ -2189,14 +2526,14 @@ "escape-string-regexp@4.0.0": { "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" }, - "eslint-plugin-react-hooks@7.0.1_eslint@9.39.1_zod@4.1.13": { + "eslint-plugin-react-hooks@7.0.1_eslint@9.39.1_zod@4.3.5": { "integrity": "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==", "dependencies": [ "@babel/core", "@babel/parser", "eslint", "hermes-parser", - "zod", + "zod@4.3.5", "zod-validation-error" ] }, @@ -2267,8 +2604,12 @@ "eslint-visitor-keys@4.2.1" ] }, - "esquery@1.6.0": { - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "esprima@4.0.1": { + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": true + }, + "esquery@1.7.0": { + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dependencies": [ "estraverse" ] @@ -2294,8 +2635,8 @@ "fast-deep-equal@3.1.3": { "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, - "fast-equals@5.3.3": { - "integrity": "sha512-/boTcHZeIAQ2r/tL11voclBHDeP9WPxLt+tyAbVSyyXuUFyh0Tne7gJZTqGbxnvj79TjLdCXLOY7UIPhyG5MTw==" + "fast-equals@5.4.0": { + "integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==" }, "fast-glob@3.3.3": { "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", @@ -2313,8 +2654,8 @@ "fast-levenshtein@2.0.6": { "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, - "fastq@1.19.1": { - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "fastq@1.20.1": { + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", "dependencies": [ "reusify" ] @@ -2393,6 +2734,12 @@ "es-object-atoms" ] }, + "get-tsconfig@4.13.0": { + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "dependencies": [ + "resolve-pkg-maps" + ] + }, "glob-parent@5.1.2": { "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dependencies": [ @@ -2411,6 +2758,12 @@ "globals@16.5.0": { "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==" }, + "goober@2.1.18_csstype@3.2.3": { + "integrity": "sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw==", + "dependencies": [ + "csstype" + ] + }, "gopd@1.2.0": { "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==" }, @@ -2463,6 +2816,12 @@ "internmap@2.0.3": { "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==" }, + "is-binary-path@2.1.0": { + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": [ + "binary-extensions" + ] + }, "is-extglob@2.1.1": { "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" }, @@ -2661,6 +3020,9 @@ "mingo@6.7.2": { "integrity": "sha512-5HKLu2GiNxw71EYZbWPh6dpcucHLlHqOXa0gbsYYtAjRpT/8EbDBJURLlUt3cNkISd9grOJ/AeYogyWj3QoxGA==" }, + "mingo@7.1.1": { + "integrity": "sha512-YfcRcZ4TRzRw1G3tf8Nu04fIoFr8hVYdTDktXU2ZLXnfn51E8yeUDixOGGQYQLduMjfznsCmEuBwzncw9lGxwA==" + }, "minimatch@3.1.2": { "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dependencies": [ @@ -2712,14 +3074,17 @@ "node-releases@2.0.27": { "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==" }, + "normalize-path@3.0.0": { + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, "object-assign@4.1.1": { "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" }, "object-inspect@1.13.4": { "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==" }, - "oidc-client-ts@2.4.1": { - "integrity": "sha512-IxlGMsbkZPsHJGCliWT3LxjUcYzmiN21656n/Zt2jDncZlBFc//cd8WqFF0Lt681UT3AImM57E6d4N53ziTCYA==", + "oidc-client-ts@2.5.0": { + "integrity": "sha512-JZ/Sp+AoML4sBWCn8ShAjnIMKx3GXwU/8sQY2btRPOUS8kBZltC2dFqOdN5Mimc4g7oVGSTC/bVDBviYcuud9g==", "dependencies": [ "crypto-js", "jwt-decode" @@ -2763,6 +3128,9 @@ "path-to-regexp@8.3.0": { "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==" }, + "pathe@2.0.3": { + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==" + }, "picocolors@1.1.1": { "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, @@ -2786,6 +3154,10 @@ "prelude-ls@1.2.1": { "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" }, + "prettier@3.7.4": { + "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", + "bin": true + }, "prop-types@15.8.1": { "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "dependencies": [ @@ -2797,8 +3169,8 @@ "punycode@2.3.1": { "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==" }, - "qs@6.14.0": { - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "qs@6.14.1": { + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", "dependencies": [ "side-channel" ] @@ -2834,8 +3206,8 @@ "@types/react" ] }, - "react-remove-scroll@2.7.1_@types+react@19.2.7_react@19.2.0": { - "integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==", + "react-remove-scroll@2.7.2_@types+react@19.2.7_react@19.2.0": { + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", "dependencies": [ "@types/react", "react", @@ -2885,6 +3257,22 @@ "react@19.2.0": { "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==" }, + "readdirp@3.6.0": { + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": [ + "picomatch@2.3.1" + ] + }, + "recast@0.23.11": { + "integrity": "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==", + "dependencies": [ + "ast-types", + "esprima", + "source-map@0.6.1", + "tiny-invariant", + "tslib" + ] + }, "recharts-scale@0.4.5": { "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", "dependencies": [ @@ -2909,11 +3297,14 @@ "resolve-from@4.0.0": { "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" }, + "resolve-pkg-maps@1.0.0": { + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==" + }, "reusify@1.1.0": { "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==" }, - "rollup@4.53.3": { - "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==", + "rollup@4.55.1": { + "integrity": "sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==", "dependencies": [ "@types/estree" ], @@ -2929,12 +3320,15 @@ "@rollup/rollup-linux-arm64-gnu", "@rollup/rollup-linux-arm64-musl", "@rollup/rollup-linux-loong64-gnu", + "@rollup/rollup-linux-loong64-musl", "@rollup/rollup-linux-ppc64-gnu", + "@rollup/rollup-linux-ppc64-musl", "@rollup/rollup-linux-riscv64-gnu", "@rollup/rollup-linux-riscv64-musl", "@rollup/rollup-linux-s390x-gnu", "@rollup/rollup-linux-x64-gnu", "@rollup/rollup-linux-x64-musl", + "@rollup/rollup-openbsd-x64", "@rollup/rollup-openharmony-arm64", "@rollup/rollup-win32-arm64-msvc", "@rollup/rollup-win32-ia32-msvc", @@ -2967,14 +3361,23 @@ "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "bin": true }, - "seroval-plugins@1.4.0_seroval@1.4.0": { - "integrity": "sha512-zir1aWzoiax6pbBVjoYVd0O1QQXgIL3eVGBMsBsNmM8Ukq90yGaWlfx0AB9dTS8GPqrOrbXn79vmItCUP9U3BQ==", + "seroval-plugins@1.3.3_seroval@1.3.2": { + "integrity": "sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w==", "dependencies": [ - "seroval" + "seroval@1.3.2" ] }, - "seroval@1.4.0": { - "integrity": "sha512-BdrNXdzlofomLTiRnwJTSEAaGKyHHZkbMXIywOh7zlzp4uZnXErEwl9XZ+N1hJSNpeTtNxWvVwN0wUzAIQ4Hpg==" + "seroval-plugins@1.4.2_seroval@1.4.2": { + "integrity": "sha512-X7p4MEDTi+60o2sXZ4bnDBhgsUYDSkQEvzYZuJyFqWg9jcoPsHts5nrg5O956py2wyt28lUrBxk0M0/wU8URpA==", + "dependencies": [ + "seroval@1.4.2" + ] + }, + "seroval@1.3.2": { + "integrity": "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==" + }, + "seroval@1.4.2": { + "integrity": "sha512-N3HEHRCZYn3cQbsC4B5ldj9j+tHdf4JZoYPlcI4rRYu0Xy4qN8MQf1Z08EibzB0WpgRG5BGK08FTrmM66eSzKQ==" }, "shebang-command@2.0.0": { "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", @@ -3021,6 +3424,14 @@ "side-channel-weakmap" ] }, + "solid-js@1.9.10_seroval@1.3.2": { + "integrity": "sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew==", + "dependencies": [ + "csstype", + "seroval@1.3.2", + "seroval-plugins@1.3.3_seroval@1.3.2" + ] + }, "sonner@2.0.7_react@19.2.0_react-dom@19.2.0__react@19.2.0": { "integrity": "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==", "dependencies": [ @@ -3031,6 +3442,12 @@ "source-map-js@1.2.1": { "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==" }, + "source-map@0.6.1": { + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map@0.7.6": { + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==" + }, "sparse-bitfield@3.0.3": { "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", "dependencies": [ @@ -3083,8 +3500,8 @@ "transit-js@0.8.874": { "integrity": "sha512-IDJJGKRzUbJHmN0P15HBBa05nbKor3r2MmG6aSt0UxXIlJZZKcddTk67/U7WyAeW9Hv/VYI02IqLzolsC4sbPA==" }, - "ts-api-utils@2.1.0_typescript@5.9.3": { - "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "ts-api-utils@2.4.0_typescript@5.9.3": { + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", "dependencies": [ "typescript" ] @@ -3092,6 +3509,17 @@ "tslib@2.8.1": { "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" }, + "tsx@4.21.0": { + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dependencies": [ + "esbuild@0.27.2", + "get-tsconfig" + ], + "optionalDependencies": [ + "fsevents" + ], + "bin": true + }, "tw-animate-css@1.4.0": { "integrity": "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==" }, @@ -3119,8 +3547,17 @@ "undici-types@7.16.0": { "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==" }, - "update-browserslist-db@1.1.4_browserslist@4.28.0": { - "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", + "unplugin@2.3.11": { + "integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==", + "dependencies": [ + "@jridgewell/remapping", + "acorn", + "picomatch@4.0.3", + "webpack-virtual-modules" + ] + }, + "update-browserslist-db@1.2.3_browserslist@4.28.1": { + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dependencies": [ "browserslist", "escalade", @@ -3198,7 +3635,7 @@ "integrity": "sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==", "dependencies": [ "@types/node", - "esbuild", + "esbuild@0.25.12", "fdir", "picomatch@4.0.3", "postcss", @@ -3216,6 +3653,9 @@ "webidl-conversions@7.0.0": { "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==" }, + "webpack-virtual-modules@0.6.2": { + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==" + }, "whatwg-url@14.2.0": { "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", "dependencies": [ @@ -3239,14 +3679,20 @@ "yocto-queue@0.1.0": { "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" }, - "zod-validation-error@4.0.2_zod@4.1.13": { + "zod-validation-error@4.0.2_zod@4.3.5": { "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", "dependencies": [ - "zod" + "zod@4.3.5" ] }, - "zod@4.1.13": { - "integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==" + "zod@3.25.76": { + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==" + }, + "zod@4.3.4": { + "integrity": "sha512-Zw/uYiiyF6pUT1qmKbZziChgNPRu+ZRneAsMUDU6IwmXdWt5JwcUfy2bvLOCUtz5UniaN/Zx5aFttZYbYc7O/A==" + }, + "zod@4.3.5": { + "integrity": "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==" } }, "workspace": { @@ -3261,7 +3707,7 @@ "api": { "packageJson": { "dependencies": [ - "npm:zod@4.1.13" + "npm:zod@4.3.5" ] } }, @@ -3273,7 +3719,7 @@ "npm:@dnd-kit/sortable@10.0.0", "npm:@dnd-kit/utilities@3.2.2", "npm:@eslint/js@9.39.1", - "npm:@jsr/valkyr__db@2.0.0", + "npm:@jsr/valkyr__db@3.0.1", "npm:@radix-ui/react-avatar@1.1.11", "npm:@radix-ui/react-checkbox@1.3.3", "npm:@radix-ui/react-collapsible@^1.1.12", @@ -3290,8 +3736,10 @@ "npm:@radix-ui/react-tooltip@1.2.8", "npm:@tabler/icons-react@3.35.0", "npm:@tailwindcss/vite@4.1.17", + "npm:@tanstack/react-router-devtools@1.144.0", "npm:@tanstack/react-router@1.139.9", "npm:@tanstack/react-table@8.21.3", + "npm:@tanstack/router-plugin@1.145.2", "npm:@types/node@24.10.1", "npm:@types/react-dom@19.2.3", "npm:@types/react@19.2.7", @@ -3318,28 +3766,28 @@ "npm:typescript@~5.9.3", "npm:vaul@1.1.2", "npm:vite@7.2.4", - "npm:zod@4.1.13" + "npm:zod@4.3.5" ] } }, "modules/account": { "packageJson": { "dependencies": [ - "npm:zod@4.1.13" + "npm:zod@4.3.5" ] } }, "modules/payment": { "packageJson": { "dependencies": [ - "npm:zod@4.1.13" + "npm:zod@4.3.5" ] } }, "modules/tenant": { "packageJson": { "dependencies": [ - "npm:zod@4.1.13" + "npm:zod@4.3.5" ] } }, @@ -3355,7 +3803,7 @@ "packageJson": { "dependencies": [ "npm:@jsr/std__dotenv@0.225.5", - "npm:zod@4.1.13" + "npm:zod@4.3.5" ] } }, @@ -3365,7 +3813,7 @@ "npm:@types/transit-js@0.8.3", "npm:postgres@3.4.7", "npm:transit-js@0.8.874", - "npm:zod@4.1.13" + "npm:zod@4.3.5" ] } }, @@ -3373,14 +3821,14 @@ "packageJson": { "dependencies": [ "npm:@jsr/valkyr__event-store@2.0.1", - "npm:zod@4.1.13" + "npm:zod@4.3.5" ] } }, "platform/parse": { "packageJson": { "dependencies": [ - "npm:zod@4.1.13" + "npm:zod@4.3.5" ] } }, @@ -3388,14 +3836,14 @@ "packageJson": { "dependencies": [ "npm:path-to-regexp@8", - "npm:zod@4.1.13" + "npm:zod@4.3.5" ] } }, "platform/routes": { "packageJson": { "dependencies": [ - "npm:zod@4.1.13" + "npm:zod@4.3.5" ] } }, @@ -3403,7 +3851,7 @@ "packageJson": { "dependencies": [ "npm:@jsr/valkyr__json-rpc@1.1.0", - "npm:zod@4.1.13" + "npm:zod@4.3.5" ] } }, @@ -3417,7 +3865,7 @@ "platform/spec": { "packageJson": { "dependencies": [ - "npm:zod@4.1.13" + "npm:zod@4.3.5" ] } }, diff --git a/docker-compose.yml b/docker-compose.yml index fb5a455..96fc5ad 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,34 +12,34 @@ services: # -------------------------------------------------------------------------------- # Used by event store and read store for managing and reading application data. - mongo: - restart: unless-stopped - image: mongo:8 - container_name: boilerplate_mongo - ports: - - 6017:27017 - environment: - MONGO_INITDB_ROOT_USERNAME: root - MONGO_INITDB_ROOT_PASSWORD: password - volumes: - - mongo:/data/db - networks: - - server + # mongo: + # restart: unless-stopped + # image: mongo:8 + # container_name: boilerplate_mongo + # ports: + # - 6017:27017 + # environment: + # MONGO_INITDB_ROOT_USERNAME: root + # MONGO_INITDB_ROOT_PASSWORD: password + # volumes: + # - mongo:/data/db + # networks: + # - server # Cerbos # -------------------------------------------------------------------------------- # Policy engine for application access control. - cerbos: - restart: unless-stopped - image: ghcr.io/cerbos/cerbos:latest - container_name: boilerplate_cerbos - command: ["server", "--config=/config.yaml"] - ports: - - 6592:3592 - - 6593:3593 - - 6594:3594 - volumes: - - ./cerbos.yaml:/config.yaml - networks: - - server + # cerbos: + # restart: unless-stopped + # image: ghcr.io/cerbos/cerbos:latest + # container_name: boilerplate_cerbos + # command: ["server", "--config=/config.yaml"] + # ports: + # - 6592:3592 + # - 6593:3593 + # - 6594:3594 + # volumes: + # - ./cerbos.yaml:/config.yaml + # networks: + # - server diff --git a/modules/account/package.json b/modules/account/package.json index 45aa34f..6b870c8 100644 --- a/modules/account/package.json +++ b/modules/account/package.json @@ -9,6 +9,6 @@ }, "dependencies": { "@platform/relay": "workspace:*", - "zod": "4.1.13" + "zod": "4.3.5" } } diff --git a/modules/payment/package.json b/modules/payment/package.json index 298dcf7..f8055e7 100644 --- a/modules/payment/package.json +++ b/modules/payment/package.json @@ -12,6 +12,6 @@ "@platform/database": "workspace:*", "@platform/parse": "workspace:*", "@platform/relay": "workspace:*", - "zod": "4.1.13" + "zod": "4.3.5" } } diff --git a/modules/payment/repositories/account.ts b/modules/payment/repositories/account.ts index 6bc3ba5..eeb677a 100644 --- a/modules/payment/repositories/account.ts +++ b/modules/payment/repositories/account.ts @@ -7,47 +7,72 @@ import { type Account, type AccountInsert, AccountInsertSchema, AccountSchema } * Create a new account. * * @param values - Account values to insert. + * + * @returns Account _id */ export async function createAccount(values: AccountInsert): Promise { return db .begin(async () => { const _id = crypto.randomUUID(); - // Assert wallet exists + // ### Assert Wallet + // Ensure that the wallet we are creating an account for exists. + await db.sql` ASSERT EXISTS ( - SELECT 1 - FROM payment.wallet w - WHERE w._id = ${db.text(values.walletId)} - ), 'missing_wallet'; + SELECT + 1 + FROM + payment.wallet wallet + WHERE + wallet._id = ${db.text(values.walletId)} + ), + 'missing_wallet'; `; - // Assert wallet → ledger relationship exists AND ledger exists + // ### Assert Wallet → Ledger + // Ensure that the wallet is related to a existing ledger. + await db.sql` ASSERT EXISTS ( - SELECT 1 - FROM payment.wallet w - JOIN payment.ledger l ON l._id = w."ledgerId" - WHERE w._id = ${db.text(values.walletId)} - ), 'missing_ledger'; + SELECT + 1 + FROM + payment.wallet wallet + JOIN + payment.ledger ledger ON ledger._id = wallet."ledgerId" + WHERE + wallet._id = ${db.text(values.walletId)} + ), + 'missing_ledger'; `; - // Assert ledger supports the currency + // ### Assert Currency + // Ensure that the account currency is supported by the ledger. + await db.sql` ASSERT EXISTS ( - SELECT 1 - FROM payment.wallet w - JOIN payment.ledger l ON l._id = w."ledgerId" - WHERE w._id = ${db.text(values.walletId)} - AND ${db.text(values.currency)} IN ( + SELECT + 1 + FROM + payment.wallet wallet + JOIN + payment.ledger ledger ON ledger._id = wallet."ledgerId" + WHERE + wallet._id = ${db.text(values.walletId)} + AND + ${db.text(values.currency)} IN ( SELECT currency FROM - UNNEST(l.currencies) AS x(currency) + UNNEST(ledger.currencies) AS x(currency) ) - ), 'unsupported_currency'; + ), + 'unsupported_currency'; `; + // ### Create Account + await db.sql`INSERT INTO payment.account RECORDS ${db.transit({ _id, ...AccountInsertSchema.parse(values) })}`; return _id; @@ -71,6 +96,13 @@ export async function createAccount(values: AccountInsert): Promise { }); } +/** + * Get all accounts registered for a wallet. + * + * @param walletId - Wallet to fetch accounts from. + * + * @returns List of wallet accounts + */ export async function getAccountsByWalletId(walletId: string): Promise { return db.schema(AccountSchema).many` SELECT diff --git a/modules/payment/repositories/beneficiary.ts b/modules/payment/repositories/beneficiary.ts index d108ea0..338c381 100644 --- a/modules/payment/repositories/beneficiary.ts +++ b/modules/payment/repositories/beneficiary.ts @@ -56,6 +56,8 @@ export async function getBeneficiaryByTenantId(tenantId: string): Promise { return db.schema(BeneficiarySchema).one` diff --git a/modules/payment/repositories/ledger.ts b/modules/payment/repositories/ledger.ts index 4f09428..d77757d 100644 --- a/modules/payment/repositories/ledger.ts +++ b/modules/payment/repositories/ledger.ts @@ -7,12 +7,31 @@ import { type Ledger, type LedgerInsert, LedgerSchema } from "../schemas/ledger. * Create a new ledger. * * @param values - Ledger values to insert. + * + * @returns Ledger _id */ export async function createLedger(values: LedgerInsert): Promise { return db .begin(async () => { const _id = crypto.randomUUID(); - await db.sql`ASSERT EXISTS (SELECT 1 FROM payment.beneficiary WHERE _id = ${db.text(values.beneficiaryId)}), 'missing_beneficiary'`; + + // ### Assert Beneficiary + // Ensure the beneficiary for the ledger exists. + + await db.sql` + ASSERT EXISTS ( + SELECT + 1 + FROM + payment.beneficiary + WHERE + _id = ${db.text(values.beneficiaryId)} + ), + 'missing_beneficiary' + `; + + // ### Create Ledger + await db.sql` INSERT INTO payment.ledger ( _id, @@ -26,6 +45,7 @@ export async function createLedger(values: LedgerInsert): Promise { ${values.label ? db.text(values.label) : null} ) `; + return _id; }) .catch((error) => { diff --git a/modules/payment/repositories/wallet.ts b/modules/payment/repositories/wallet.ts index 3ec552b..774a056 100644 --- a/modules/payment/repositories/wallet.ts +++ b/modules/payment/repositories/wallet.ts @@ -7,13 +7,33 @@ import { type Wallet, type WalletInsert, WalletInsertSchema, WalletSchema } from * Create a new wallet. * * @param values - Wallet values to insert. + * + * @returns Wallet _id */ export async function createWallet(values: WalletInsert): Promise { return db .begin(async () => { const _id = crypto.randomUUID(); - await db.sql`ASSERT EXISTS (SELECT 1 FROM payment.ledger WHERE _id = ${db.text(values.ledgerId)}), 'missing_ledger'`; + + // ### Assert Ledger + // Ensure the ledger for the wallet exists. + + await db.sql` + ASSERT EXISTS ( + SELECT + 1 + FROM + payment.ledger + WHERE + _id = ${db.text(values.ledgerId)} + ), + 'missing_ledger' + `; + + // ### Create Wallet + await db.sql`INSERT INTO payment.wallet RECORDS ${db.transit({ _id, ...WalletInsertSchema.parse(values) })}`; + return _id; }) .catch((error) => { diff --git a/modules/tenant/package.json b/modules/tenant/package.json index 16919db..f5148ef 100644 --- a/modules/tenant/package.json +++ b/modules/tenant/package.json @@ -11,6 +11,6 @@ "@platform/database": "workspace:*", "@platform/parse": "workspace:*", "@platform/relay": "workspace:*", - "zod": "4.1.13" + "zod": "4.3.5" } } diff --git a/platform/config/package.json b/platform/config/package.json index 893c49c..31fdd45 100644 --- a/platform/config/package.json +++ b/platform/config/package.json @@ -9,6 +9,6 @@ }, "dependencies": { "@std/dotenv": "npm:@jsr/std__dotenv@0.225.5", - "zod": "4.1.13" + "zod": "4.3.5" } } diff --git a/platform/database/package.json b/platform/database/package.json index 427ad1c..9f031be 100644 --- a/platform/database/package.json +++ b/platform/database/package.json @@ -13,6 +13,6 @@ "@types/transit-js": "0.8.3", "postgres": "3.4.7", "transit-js": "0.8.874", - "zod": "4.1.13" + "zod": "4.3.5" } } diff --git a/platform/logger/package.json b/platform/logger/package.json index 108a657..dd13667 100644 --- a/platform/logger/package.json +++ b/platform/logger/package.json @@ -10,6 +10,6 @@ "dependencies": { "@platform/config": "workspace:*", "@valkyr/event-store": "npm:@jsr/valkyr__event-store@2.0.1", - "zod": "4.1.13" + "zod": "4.3.5" } } diff --git a/platform/parse/package.json b/platform/parse/package.json index ac6ccfe..f0c7dbf 100644 --- a/platform/parse/package.json +++ b/platform/parse/package.json @@ -8,6 +8,6 @@ ".": "./mod.ts" }, "dependencies": { - "zod": "4.1.13" + "zod": "4.3.5" } } diff --git a/platform/relay/package.json b/platform/relay/package.json index e487673..2569913 100644 --- a/platform/relay/package.json +++ b/platform/relay/package.json @@ -12,6 +12,6 @@ "@platform/socket": "workspace:*", "@platform/supertokens": "workspace:*", "path-to-regexp": "8", - "zod": "4.1.13" + "zod": "4.3.5" } } diff --git a/platform/routes/package.json b/platform/routes/package.json index 317e0ad..6a95188 100644 --- a/platform/routes/package.json +++ b/platform/routes/package.json @@ -5,6 +5,6 @@ "type": "module", "dependencies": { "@platform/relay": "workspace:*", - "zod": "4.1.13" + "zod": "4.3.5" } } diff --git a/platform/server/package.json b/platform/server/package.json index ececc67..91ec36c 100644 --- a/platform/server/package.json +++ b/platform/server/package.json @@ -11,6 +11,6 @@ "@platform/socket": "workspace:*", "@platform/storage": "workspace:*", "@valkyr/json-rpc": "npm:@jsr/valkyr__json-rpc@1.1.0", - "zod": "4.1.13" + "zod": "4.3.5" } } diff --git a/platform/spec/package.json b/platform/spec/package.json index 0f057d2..2b28311 100644 --- a/platform/spec/package.json +++ b/platform/spec/package.json @@ -6,6 +6,6 @@ "dependencies": { "@platform/models": "workspace:*", "@platform/relay": "workspace:*", - "zod": "4.1.13" + "zod": "4.3.5" } }