From a3af29ec4ec0d87f9b92e887d6923df095fd87b6 Mon Sep 17 00:00:00 2001 From: Nicolas Meienberger Date: Sat, 14 Feb 2026 15:43:24 +0100 Subject: [PATCH] feat: oidc feat: organization switcher refactor: org context feat: invitations GLM --- .oxfmtrc.json | 3 +- AGENTS.md | 2 + .../api-client/@tanstack/react-query.gen.ts | 2259 ++--- app/client/api-client/client/client.gen.ts | 483 +- app/client/api-client/client/types.gen.ts | 302 +- app/client/api-client/client/utils.gen.ts | 463 +- app/client/api-client/core/auth.gen.ts | 54 +- .../api-client/core/bodySerializer.gen.ts | 104 +- app/client/api-client/core/params.gen.ts | 260 +- .../api-client/core/pathSerializer.gen.ts | 254 +- .../api-client/core/queryKeySerializer.gen.ts | 136 +- .../api-client/core/serverSentEvents.gen.ts | 400 +- app/client/api-client/core/types.gen.ts | 162 +- app/client/api-client/core/utils.gen.ts | 211 +- app/client/api-client/index.ts | 20 + app/client/api-client/sdk.gen.ts | 836 +- app/client/api-client/types.gen.ts | 8273 ++++++++--------- app/client/components/app-sidebar.tsx | 4 +- app/client/components/layout.tsx | 2 +- .../components/organization-switcher.tsx | 106 + app/client/components/ui/dropdown-menu.tsx | 217 + app/client/components/ui/popover.tsx | 52 + app/client/functions/get-origin.ts | 6 + app/client/hooks/use-org-context.ts | 13 + app/client/lib/auth-client.ts | 2 + app/client/lib/auth-errors.ts | 62 + .../auth/routes/__tests__/login.test.tsx | 39 + app/client/modules/auth/routes/login.tsx | 66 +- .../components/sso/sso-settings-section.tsx | 549 ++ .../settings/components/user-management.tsx | 104 +- .../modules/settings/routes/settings.tsx | 20 +- app/context.ts | 1 + .../migration.sql | 18 + .../snapshot.json | 2210 +++++ app/middleware/auth.ts | 20 +- app/routeTree.gen.ts | 149 +- app/routes/(auth)/login.error.tsx | 23 + app/routes/(auth)/login.tsx | 19 +- app/routes/(auth)/route.tsx | 9 + app/routes/(dashboard)/settings/index.tsx | 11 +- .../(dashboard)/settings/sso-link.error.tsx | 10 + app/routes/(dashboard)/settings/sso-link.tsx | 10 + app/server/db/relations.ts | 14 + app/server/db/schema.ts | 31 + app/server/lib/auth.ts | 90 +- .../__tests__/create-default-org.test.ts | 130 + .../lib/auth/helpers/create-default-org.ts | 194 + .../__tests__/convert-legacy-user.test.ts | 2 +- .../__tests__/require-sso-invitation.test.ts | 124 + .../middlewares}/convert-legacy-user.ts | 2 +- .../middlewares}/only-one-user.ts | 2 +- .../middlewares/require-sso-invitation.ts | 66 + app/server/lib/auth/utils/sso-context.ts | 21 + .../lib/functions/organization-context.ts | 25 + app/server/modules/auth/auth.controller.ts | 85 +- app/server/modules/auth/auth.dto.ts | 118 + app/server/modules/auth/auth.service.ts | 37 +- bun.lock | 408 +- package.json | 2 + 59 files changed, 11469 insertions(+), 7826 deletions(-) create mode 100644 app/client/components/organization-switcher.tsx create mode 100644 app/client/components/ui/dropdown-menu.tsx create mode 100644 app/client/components/ui/popover.tsx create mode 100644 app/client/functions/get-origin.ts create mode 100644 app/client/hooks/use-org-context.ts create mode 100644 app/client/lib/auth-errors.ts create mode 100644 app/client/modules/auth/routes/__tests__/login.test.tsx create mode 100644 app/client/modules/settings/components/sso/sso-settings-section.tsx create mode 100644 app/drizzle/20260214144113_mighty_meggan/migration.sql create mode 100644 app/drizzle/20260214144113_mighty_meggan/snapshot.json create mode 100644 app/routes/(auth)/login.error.tsx create mode 100644 app/routes/(auth)/route.tsx create mode 100644 app/routes/(dashboard)/settings/sso-link.error.tsx create mode 100644 app/routes/(dashboard)/settings/sso-link.tsx create mode 100644 app/server/lib/auth/helpers/__tests__/create-default-org.test.ts create mode 100644 app/server/lib/auth/helpers/create-default-org.ts rename app/server/lib/{auth-middlewares => auth/middlewares}/__tests__/convert-legacy-user.test.ts (99%) create mode 100644 app/server/lib/auth/middlewares/__tests__/require-sso-invitation.test.ts rename app/server/lib/{auth-middlewares => auth/middlewares}/convert-legacy-user.ts (98%) rename app/server/lib/{auth-middlewares => auth/middlewares}/only-one-user.ts (92%) create mode 100644 app/server/lib/auth/middlewares/require-sso-invitation.ts create mode 100644 app/server/lib/auth/utils/sso-context.ts create mode 100644 app/server/lib/functions/organization-context.ts diff --git a/.oxfmtrc.json b/.oxfmtrc.json index 988352d8..17174df4 100644 --- a/.oxfmtrc.json +++ b/.oxfmtrc.json @@ -2,5 +2,6 @@ "$schema": "./node_modules/oxfmt/configuration_schema.json", "printWidth": 120, "useTabs": true, - "endOfLine": "lf" + "endOfLine": "lf", + "ignorePatterns": ["*.gen.ts"] } diff --git a/AGENTS.md b/AGENTS.md index a1ce055b..52f3e8fc 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -60,3 +60,5 @@ bunx oxfmt format --write # Lint bun run lint ``` + +The frontend has an automatic invalidation setup which runs after every mutation, do not write any invalidation logic in the frontend. diff --git a/app/client/api-client/@tanstack/react-query.gen.ts b/app/client/api-client/@tanstack/react-query.gen.ts index 95287be8..73fba713 100644 --- a/app/client/api-client/@tanstack/react-query.gen.ts +++ b/app/client/api-client/@tanstack/react-query.gen.ts @@ -1,1643 +1,1258 @@ // @ts-nocheck // This file is auto-generated by @hey-api/openapi-ts -import { - type DefaultError, - type InfiniteData, - infiniteQueryOptions, - queryOptions, - type UseMutationOptions, -} from "@tanstack/react-query"; +import { type DefaultError, type InfiniteData, infiniteQueryOptions, queryOptions, type UseMutationOptions } from '@tanstack/react-query'; -import { client } from "../client.gen"; -import { - browseFilesystem, - cancelDoctor, - createBackupSchedule, - createNotificationDestination, - createRepository, - createVolume, - deleteBackupSchedule, - deleteNotificationDestination, - deleteRepository, - deleteSnapshot, - deleteSnapshots, - deleteVolume, - devPanelExec, - downloadResticPassword, - dumpSnapshot, - getBackupSchedule, - getBackupScheduleForVolume, - getDevPanel, - getMirrorCompatibility, - getNotificationDestination, - getRegistrationStatus, - getRepository, - getRepositoryStats, - getScheduleMirrors, - getScheduleNotifications, - getSnapshotDetails, - getStatus, - getSystemInfo, - getUpdates, - getUserDeletionImpact, - getVolume, - healthCheckVolume, - listBackupSchedules, - listFiles, - listNotificationDestinations, - listRcloneRemotes, - listRepositories, - listSnapshotFiles, - listSnapshots, - listVolumes, - mountVolume, - type Options, - refreshSnapshots, - reorderBackupSchedules, - restoreSnapshot, - runBackupNow, - runForget, - setRegistrationStatus, - startDoctor, - stopBackup, - tagSnapshots, - testConnection, - testNotificationDestination, - unlockRepository, - unmountVolume, - updateBackupSchedule, - updateNotificationDestination, - updateRepository, - updateScheduleMirrors, - updateScheduleNotifications, - updateVolume, -} from "../sdk.gen"; -import type { - BrowseFilesystemData, - BrowseFilesystemResponse, - CancelDoctorData, - CancelDoctorResponse, - CreateBackupScheduleData, - CreateBackupScheduleResponse, - CreateNotificationDestinationData, - CreateNotificationDestinationResponse, - CreateRepositoryData, - CreateRepositoryResponse, - CreateVolumeData, - CreateVolumeResponse, - DeleteBackupScheduleData, - DeleteBackupScheduleResponse, - DeleteNotificationDestinationData, - DeleteNotificationDestinationResponse, - DeleteRepositoryData, - DeleteRepositoryResponse, - DeleteSnapshotData, - DeleteSnapshotResponse, - DeleteSnapshotsData, - DeleteSnapshotsResponse, - DeleteVolumeData, - DeleteVolumeResponse, - DevPanelExecData, - DevPanelExecResponse, - DownloadResticPasswordData, - DownloadResticPasswordResponse, - DumpSnapshotData, - DumpSnapshotResponse, - GetBackupScheduleData, - GetBackupScheduleForVolumeData, - GetBackupScheduleForVolumeResponse, - GetBackupScheduleResponse, - GetDevPanelData, - GetDevPanelResponse, - GetMirrorCompatibilityData, - GetMirrorCompatibilityResponse, - GetNotificationDestinationData, - GetNotificationDestinationResponse, - GetRegistrationStatusData, - GetRegistrationStatusResponse, - GetRepositoryData, - GetRepositoryResponse, - GetRepositoryStatsData, - GetRepositoryStatsResponse, - GetScheduleMirrorsData, - GetScheduleMirrorsResponse, - GetScheduleNotificationsData, - GetScheduleNotificationsResponse, - GetSnapshotDetailsData, - GetSnapshotDetailsResponse, - GetStatusData, - GetStatusResponse, - GetSystemInfoData, - GetSystemInfoResponse, - GetUpdatesData, - GetUpdatesResponse, - GetUserDeletionImpactData, - GetUserDeletionImpactResponse, - GetVolumeData, - GetVolumeResponse, - HealthCheckVolumeData, - HealthCheckVolumeResponse, - ListBackupSchedulesData, - ListBackupSchedulesResponse, - ListFilesData, - ListFilesResponse, - ListNotificationDestinationsData, - ListNotificationDestinationsResponse, - ListRcloneRemotesData, - ListRcloneRemotesResponse, - ListRepositoriesData, - ListRepositoriesResponse, - ListSnapshotFilesData, - ListSnapshotFilesResponse, - ListSnapshotsData, - ListSnapshotsResponse, - ListVolumesData, - ListVolumesResponse, - MountVolumeData, - MountVolumeResponse, - RefreshSnapshotsData, - RefreshSnapshotsResponse, - ReorderBackupSchedulesData, - ReorderBackupSchedulesResponse, - RestoreSnapshotData, - RestoreSnapshotResponse, - RunBackupNowData, - RunBackupNowResponse, - RunForgetData, - RunForgetResponse, - SetRegistrationStatusData, - SetRegistrationStatusResponse, - StartDoctorData, - StartDoctorResponse, - StopBackupData, - StopBackupResponse, - TagSnapshotsData, - TagSnapshotsResponse, - TestConnectionData, - TestConnectionResponse, - TestNotificationDestinationData, - TestNotificationDestinationResponse, - UnlockRepositoryData, - UnlockRepositoryResponse, - UnmountVolumeData, - UnmountVolumeResponse, - UpdateBackupScheduleData, - UpdateBackupScheduleResponse, - UpdateNotificationDestinationData, - UpdateNotificationDestinationResponse, - UpdateRepositoryData, - UpdateRepositoryResponse, - UpdateScheduleMirrorsData, - UpdateScheduleMirrorsResponse, - UpdateScheduleNotificationsData, - UpdateScheduleNotificationsResponse, - UpdateVolumeData, - UpdateVolumeResponse, -} from "../types.gen"; +import { client } from '../client.gen'; +import { browseFilesystem, cancelDoctor, createBackupSchedule, createNotificationDestination, createRepository, createVolume, deleteBackupSchedule, deleteNotificationDestination, deleteRepository, deleteSnapshot, deleteSnapshots, deleteSsoInvitation, deleteSsoProvider, deleteVolume, devPanelExec, downloadResticPassword, dumpSnapshot, getAdminUsers, getBackupSchedule, getBackupScheduleForVolume, getDevPanel, getMirrorCompatibility, getNotificationDestination, getPublicSsoProviders, getRegistrationStatus, getRepository, getRepositoryStats, getScheduleMirrors, getScheduleNotifications, getSnapshotDetails, getSsoSettings, getStatus, getSystemInfo, getUpdates, getUserDeletionImpact, getVolume, healthCheckVolume, listBackupSchedules, listFiles, listNotificationDestinations, listRcloneRemotes, listRepositories, listSnapshotFiles, listSnapshots, listVolumes, mountVolume, type Options, refreshSnapshots, reorderBackupSchedules, restoreSnapshot, runBackupNow, runForget, setRegistrationStatus, startDoctor, stopBackup, tagSnapshots, testConnection, testNotificationDestination, unlockRepository, unmountVolume, updateBackupSchedule, updateNotificationDestination, updateRepository, updateScheduleMirrors, updateScheduleNotifications, updateVolume } from '../sdk.gen'; +import type { BrowseFilesystemData, BrowseFilesystemResponse, CancelDoctorData, CancelDoctorResponse, CreateBackupScheduleData, CreateBackupScheduleResponse, CreateNotificationDestinationData, CreateNotificationDestinationResponse, CreateRepositoryData, CreateRepositoryResponse, CreateVolumeData, CreateVolumeResponse, DeleteBackupScheduleData, DeleteBackupScheduleResponse, DeleteNotificationDestinationData, DeleteNotificationDestinationResponse, DeleteRepositoryData, DeleteRepositoryResponse, DeleteSnapshotData, DeleteSnapshotResponse, DeleteSnapshotsData, DeleteSnapshotsResponse, DeleteSsoInvitationData, DeleteSsoProviderData, DeleteVolumeData, DeleteVolumeResponse, DevPanelExecData, DevPanelExecResponse, DownloadResticPasswordData, DownloadResticPasswordResponse, DumpSnapshotData, DumpSnapshotResponse, GetAdminUsersData, GetAdminUsersResponse, GetBackupScheduleData, GetBackupScheduleForVolumeData, GetBackupScheduleForVolumeResponse, GetBackupScheduleResponse, GetDevPanelData, GetDevPanelResponse, GetMirrorCompatibilityData, GetMirrorCompatibilityResponse, GetNotificationDestinationData, GetNotificationDestinationResponse, GetPublicSsoProvidersData, GetPublicSsoProvidersResponse, GetRegistrationStatusData, GetRegistrationStatusResponse, GetRepositoryData, GetRepositoryResponse, GetRepositoryStatsData, GetRepositoryStatsResponse, GetScheduleMirrorsData, GetScheduleMirrorsResponse, GetScheduleNotificationsData, GetScheduleNotificationsResponse, GetSnapshotDetailsData, GetSnapshotDetailsResponse, GetSsoSettingsData, GetSsoSettingsResponse, GetStatusData, GetStatusResponse, GetSystemInfoData, GetSystemInfoResponse, GetUpdatesData, GetUpdatesResponse, GetUserDeletionImpactData, GetUserDeletionImpactResponse, GetVolumeData, GetVolumeResponse, HealthCheckVolumeData, HealthCheckVolumeResponse, ListBackupSchedulesData, ListBackupSchedulesResponse, ListFilesData, ListFilesResponse, ListNotificationDestinationsData, ListNotificationDestinationsResponse, ListRcloneRemotesData, ListRcloneRemotesResponse, ListRepositoriesData, ListRepositoriesResponse, ListSnapshotFilesData, ListSnapshotFilesResponse, ListSnapshotsData, ListSnapshotsResponse, ListVolumesData, ListVolumesResponse, MountVolumeData, MountVolumeResponse, RefreshSnapshotsData, RefreshSnapshotsResponse, ReorderBackupSchedulesData, ReorderBackupSchedulesResponse, RestoreSnapshotData, RestoreSnapshotResponse, RunBackupNowData, RunBackupNowResponse, RunForgetData, RunForgetResponse, SetRegistrationStatusData, SetRegistrationStatusResponse, StartDoctorData, StartDoctorResponse, StopBackupData, StopBackupResponse, TagSnapshotsData, TagSnapshotsResponse, TestConnectionData, TestConnectionResponse, TestNotificationDestinationData, TestNotificationDestinationResponse, UnlockRepositoryData, UnlockRepositoryResponse, UnmountVolumeData, UnmountVolumeResponse, UpdateBackupScheduleData, UpdateBackupScheduleResponse, UpdateNotificationDestinationData, UpdateNotificationDestinationResponse, UpdateRepositoryData, UpdateRepositoryResponse, UpdateScheduleMirrorsData, UpdateScheduleMirrorsResponse, UpdateScheduleNotificationsData, UpdateScheduleNotificationsResponse, UpdateVolumeData, UpdateVolumeResponse } from '../types.gen'; export type QueryKey = [ - Pick & { - _id: string; - _infinite?: boolean; - tags?: ReadonlyArray; - }, + Pick & { + _id: string; + _infinite?: boolean; + tags?: ReadonlyArray; + } ]; -const createQueryKey = ( - id: string, - options?: TOptions, - infinite?: boolean, - tags?: ReadonlyArray, -): [QueryKey[0]] => { - const params: QueryKey[0] = { - _id: id, - baseUrl: options?.baseUrl || (options?.client ?? client).getConfig().baseUrl, - } as QueryKey[0]; - if (infinite) { - params._infinite = infinite; - } - if (tags) { - params.tags = tags; - } - if (options?.body) { - params.body = options.body; - } - if (options?.headers) { - params.headers = options.headers; - } - if (options?.path) { - params.path = options.path; - } - if (options?.query) { - params.query = options.query; - } - return [params]; +const createQueryKey = (id: string, options?: TOptions, infinite?: boolean, tags?: ReadonlyArray): [ + QueryKey[0] +] => { + const params: QueryKey[0] = { _id: id, baseUrl: options?.baseUrl || (options?.client ?? client).getConfig().baseUrl } as QueryKey[0]; + if (infinite) { + params._infinite = infinite; + } + if (tags) { + params.tags = tags; + } + if (options?.body) { + params.body = options.body; + } + if (options?.headers) { + params.headers = options.headers; + } + if (options?.path) { + params.path = options.path; + } + if (options?.query) { + params.query = options.query; + } + return [params]; }; -export const getStatusQueryKey = (options?: Options) => createQueryKey("getStatus", options); +export const getStatusQueryKey = (options?: Options) => createQueryKey('getStatus', options); /** * Get authentication system status */ -export const getStatusOptions = (options?: Options) => - queryOptions>({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await getStatus({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: getStatusQueryKey(options), - }); +export const getStatusOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getStatus({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getStatusQueryKey(options) +}); -export const getUserDeletionImpactQueryKey = (options: Options) => - createQueryKey("getUserDeletionImpact", options); +export const getPublicSsoProvidersQueryKey = (options?: Options) => createQueryKey('getPublicSsoProviders', options); + +/** + * Get public SSO providers for the instance + */ +export const getPublicSsoProvidersOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getPublicSsoProviders({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getPublicSsoProvidersQueryKey(options) +}); + +export const getSsoSettingsQueryKey = (options?: Options) => createQueryKey('getSsoSettings', options); + +/** + * Get SSO providers and invitations for the active organization + */ +export const getSsoSettingsOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getSsoSettings({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getSsoSettingsQueryKey(options) +}); + +/** + * Delete an SSO provider + */ +export const deleteSsoProviderMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await deleteSsoProvider({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Delete an SSO invitation + */ +export const deleteSsoInvitationMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await deleteSsoInvitation({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getAdminUsersQueryKey = (options?: Options) => createQueryKey('getAdminUsers', options); + +/** + * List admin users for settings management + */ +export const getAdminUsersOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getAdminUsers({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getAdminUsersQueryKey(options) +}); + +export const getUserDeletionImpactQueryKey = (options: Options) => createQueryKey('getUserDeletionImpact', options); /** * Get impact of deleting a user */ -export const getUserDeletionImpactOptions = (options: Options) => - queryOptions< - GetUserDeletionImpactResponse, - DefaultError, - GetUserDeletionImpactResponse, - ReturnType - >({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await getUserDeletionImpact({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: getUserDeletionImpactQueryKey(options), - }); +export const getUserDeletionImpactOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getUserDeletionImpact({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getUserDeletionImpactQueryKey(options) +}); -export const listVolumesQueryKey = (options?: Options) => createQueryKey("listVolumes", options); +export const listVolumesQueryKey = (options?: Options) => createQueryKey('listVolumes', options); /** * List all volumes */ -export const listVolumesOptions = (options?: Options) => - queryOptions>({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await listVolumes({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: listVolumesQueryKey(options), - }); +export const listVolumesOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await listVolumes({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: listVolumesQueryKey(options) +}); /** * Create a new volume */ -export const createVolumeMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions> = { - mutationFn: async (fnOptions) => { - const { data } = await createVolume({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const createVolumeMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await createVolume({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; /** * Test connection to backend */ -export const testConnectionMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions> = { - mutationFn: async (fnOptions) => { - const { data } = await testConnection({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const testConnectionMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await testConnection({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; /** * Delete a volume */ -export const deleteVolumeMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions> = { - mutationFn: async (fnOptions) => { - const { data } = await deleteVolume({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const deleteVolumeMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await deleteVolume({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; -export const getVolumeQueryKey = (options: Options) => createQueryKey("getVolume", options); +export const getVolumeQueryKey = (options: Options) => createQueryKey('getVolume', options); /** * Get a volume by name */ -export const getVolumeOptions = (options: Options) => - queryOptions>({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await getVolume({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: getVolumeQueryKey(options), - }); +export const getVolumeOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getVolume({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getVolumeQueryKey(options) +}); /** * Update a volume's configuration */ -export const updateVolumeMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions> = { - mutationFn: async (fnOptions) => { - const { data } = await updateVolume({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const updateVolumeMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await updateVolume({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; /** * Mount a volume */ -export const mountVolumeMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions> = { - mutationFn: async (fnOptions) => { - const { data } = await mountVolume({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const mountVolumeMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await mountVolume({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; /** * Unmount a volume */ -export const unmountVolumeMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions> = { - mutationFn: async (fnOptions) => { - const { data } = await unmountVolume({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const unmountVolumeMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await unmountVolume({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; /** * Perform a health check on a volume */ -export const healthCheckVolumeMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions> = { - mutationFn: async (fnOptions) => { - const { data } = await healthCheckVolume({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const healthCheckVolumeMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await healthCheckVolume({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; -export const listFilesQueryKey = (options: Options) => createQueryKey("listFiles", options); +export const listFilesQueryKey = (options: Options) => createQueryKey('listFiles', options); /** * List files in a volume directory */ -export const listFilesOptions = (options: Options) => - queryOptions>({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await listFiles({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: listFilesQueryKey(options), - }); +export const listFilesOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await listFiles({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: listFilesQueryKey(options) +}); -const createInfiniteParams = [0], "body" | "headers" | "path" | "query">>( - queryKey: QueryKey, - page: K, -) => { - const params = { ...queryKey[0] }; - if (page.body) { - params.body = { - ...(queryKey[0].body as any), - ...(page.body as any), - }; - } - if (page.headers) { - params.headers = { - ...queryKey[0].headers, - ...page.headers, - }; - } - if (page.path) { - params.path = { - ...(queryKey[0].path as any), - ...(page.path as any), - }; - } - if (page.query) { - params.query = { - ...(queryKey[0].query as any), - ...(page.query as any), - }; - } - return params as unknown as typeof page; +const createInfiniteParams = [0], 'body' | 'headers' | 'path' | 'query'>>(queryKey: QueryKey, page: K) => { + const params = { ...queryKey[0] }; + if (page.body) { + params.body = { + ...queryKey[0].body as any, + ...page.body as any + }; + } + if (page.headers) { + params.headers = { + ...queryKey[0].headers, + ...page.headers + }; + } + if (page.path) { + params.path = { + ...queryKey[0].path as any, + ...page.path as any + }; + } + if (page.query) { + params.query = { + ...queryKey[0].query as any, + ...page.query as any + }; + } + return params as unknown as typeof page; }; -export const listFilesInfiniteQueryKey = (options: Options): QueryKey> => - createQueryKey("listFiles", options, true); +export const listFilesInfiniteQueryKey = (options: Options): QueryKey> => createQueryKey('listFiles', options, true); /** * List files in a volume directory */ -export const listFilesInfiniteOptions = (options: Options) => - infiniteQueryOptions< - ListFilesResponse, - DefaultError, - InfiniteData, - QueryKey>, - string | Pick>[0], "body" | "headers" | "path" | "query"> - >( - // @ts-ignore - { - queryFn: async ({ pageParam, queryKey, signal }) => { - // @ts-ignore - const page: Pick>[0], "body" | "headers" | "path" | "query"> = - typeof pageParam === "object" - ? pageParam - : { - query: { - offset: pageParam, - }, - }; - const params = createInfiniteParams(queryKey, page); - const { data } = await listFiles({ - ...options, - ...params, - signal, - throwOnError: true, - }); - return data; - }, - queryKey: listFilesInfiniteQueryKey(options), - }, - ); +export const listFilesInfiniteOptions = (options: Options) => infiniteQueryOptions, QueryKey>, string | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( +// @ts-ignore +{ + queryFn: async ({ pageParam, queryKey, signal }) => { + // @ts-ignore + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { + query: { + offset: pageParam + } + }; + const params = createInfiniteParams(queryKey, page); + const { data } = await listFiles({ + ...options, + ...params, + signal, + throwOnError: true + }); + return data; + }, + queryKey: listFilesInfiniteQueryKey(options) +}); -export const browseFilesystemQueryKey = (options?: Options) => - createQueryKey("browseFilesystem", options); +export const browseFilesystemQueryKey = (options?: Options) => createQueryKey('browseFilesystem', options); /** * Browse directories on the host filesystem */ -export const browseFilesystemOptions = (options?: Options) => - queryOptions< - BrowseFilesystemResponse, - DefaultError, - BrowseFilesystemResponse, - ReturnType - >({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await browseFilesystem({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: browseFilesystemQueryKey(options), - }); +export const browseFilesystemOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await browseFilesystem({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: browseFilesystemQueryKey(options) +}); -export const listRepositoriesQueryKey = (options?: Options) => - createQueryKey("listRepositories", options); +export const listRepositoriesQueryKey = (options?: Options) => createQueryKey('listRepositories', options); /** * List all repositories */ -export const listRepositoriesOptions = (options?: Options) => - queryOptions< - ListRepositoriesResponse, - DefaultError, - ListRepositoriesResponse, - ReturnType - >({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await listRepositories({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: listRepositoriesQueryKey(options), - }); +export const listRepositoriesOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await listRepositories({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: listRepositoriesQueryKey(options) +}); /** * Create a new restic repository */ -export const createRepositoryMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions> = { - mutationFn: async (fnOptions) => { - const { data } = await createRepository({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const createRepositoryMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await createRepository({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; -export const listRcloneRemotesQueryKey = (options?: Options) => - createQueryKey("listRcloneRemotes", options); +export const listRcloneRemotesQueryKey = (options?: Options) => createQueryKey('listRcloneRemotes', options); /** * List all configured rclone remotes on the host system */ -export const listRcloneRemotesOptions = (options?: Options) => - queryOptions< - ListRcloneRemotesResponse, - DefaultError, - ListRcloneRemotesResponse, - ReturnType - >({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await listRcloneRemotes({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: listRcloneRemotesQueryKey(options), - }); +export const listRcloneRemotesOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await listRcloneRemotes({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: listRcloneRemotesQueryKey(options) +}); /** * Delete a repository */ -export const deleteRepositoryMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions> = { - mutationFn: async (fnOptions) => { - const { data } = await deleteRepository({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const deleteRepositoryMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await deleteRepository({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; -export const getRepositoryQueryKey = (options: Options) => createQueryKey("getRepository", options); +export const getRepositoryQueryKey = (options: Options) => createQueryKey('getRepository', options); /** * Get a single repository by ID */ -export const getRepositoryOptions = (options: Options) => - queryOptions>({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await getRepository({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: getRepositoryQueryKey(options), - }); +export const getRepositoryOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getRepository({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getRepositoryQueryKey(options) +}); /** * Update a repository's name or settings */ -export const updateRepositoryMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions> = { - mutationFn: async (fnOptions) => { - const { data } = await updateRepository({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const updateRepositoryMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await updateRepository({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; -export const getRepositoryStatsQueryKey = (options: Options) => - createQueryKey("getRepositoryStats", options); +export const getRepositoryStatsQueryKey = (options: Options) => createQueryKey('getRepositoryStats', options); /** * Get repository storage and compression statistics */ -export const getRepositoryStatsOptions = (options: Options) => - queryOptions< - GetRepositoryStatsResponse, - DefaultError, - GetRepositoryStatsResponse, - ReturnType - >({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await getRepositoryStats({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: getRepositoryStatsQueryKey(options), - }); +export const getRepositoryStatsOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getRepositoryStats({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getRepositoryStatsQueryKey(options) +}); /** * Delete multiple snapshots from a repository */ -export const deleteSnapshotsMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions> = { - mutationFn: async (fnOptions) => { - const { data } = await deleteSnapshots({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const deleteSnapshotsMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await deleteSnapshots({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; -export const listSnapshotsQueryKey = (options: Options) => createQueryKey("listSnapshots", options); +export const listSnapshotsQueryKey = (options: Options) => createQueryKey('listSnapshots', options); /** * List all snapshots in a repository */ -export const listSnapshotsOptions = (options: Options) => - queryOptions>({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await listSnapshots({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: listSnapshotsQueryKey(options), - }); +export const listSnapshotsOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await listSnapshots({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: listSnapshotsQueryKey(options) +}); /** * Clear snapshot cache and force refresh from repository */ -export const refreshSnapshotsMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions> = { - mutationFn: async (fnOptions) => { - const { data } = await refreshSnapshots({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const refreshSnapshotsMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await refreshSnapshots({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; /** * Delete a specific snapshot from a repository */ -export const deleteSnapshotMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions> = { - mutationFn: async (fnOptions) => { - const { data } = await deleteSnapshot({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const deleteSnapshotMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await deleteSnapshot({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; -export const getSnapshotDetailsQueryKey = (options: Options) => - createQueryKey("getSnapshotDetails", options); +export const getSnapshotDetailsQueryKey = (options: Options) => createQueryKey('getSnapshotDetails', options); /** * Get details of a specific snapshot */ -export const getSnapshotDetailsOptions = (options: Options) => - queryOptions< - GetSnapshotDetailsResponse, - DefaultError, - GetSnapshotDetailsResponse, - ReturnType - >({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await getSnapshotDetails({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: getSnapshotDetailsQueryKey(options), - }); +export const getSnapshotDetailsOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getSnapshotDetails({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getSnapshotDetailsQueryKey(options) +}); -export const listSnapshotFilesQueryKey = (options: Options) => - createQueryKey("listSnapshotFiles", options); +export const listSnapshotFilesQueryKey = (options: Options) => createQueryKey('listSnapshotFiles', options); /** * List files and directories in a snapshot */ -export const listSnapshotFilesOptions = (options: Options) => - queryOptions< - ListSnapshotFilesResponse, - DefaultError, - ListSnapshotFilesResponse, - ReturnType - >({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await listSnapshotFiles({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: listSnapshotFilesQueryKey(options), - }); +export const listSnapshotFilesOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await listSnapshotFiles({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: listSnapshotFilesQueryKey(options) +}); -export const listSnapshotFilesInfiniteQueryKey = ( - options: Options, -): QueryKey> => createQueryKey("listSnapshotFiles", options, true); +export const listSnapshotFilesInfiniteQueryKey = (options: Options): QueryKey> => createQueryKey('listSnapshotFiles', options, true); /** * List files and directories in a snapshot */ -export const listSnapshotFilesInfiniteOptions = (options: Options) => - infiniteQueryOptions< - ListSnapshotFilesResponse, - DefaultError, - InfiniteData, - QueryKey>, - string | Pick>[0], "body" | "headers" | "path" | "query"> - >( - // @ts-ignore - { - queryFn: async ({ pageParam, queryKey, signal }) => { - // @ts-ignore - const page: Pick>[0], "body" | "headers" | "path" | "query"> = - typeof pageParam === "object" - ? pageParam - : { - query: { - offset: pageParam, - }, - }; - const params = createInfiniteParams(queryKey, page); - const { data } = await listSnapshotFiles({ - ...options, - ...params, - signal, - throwOnError: true, - }); - return data; - }, - queryKey: listSnapshotFilesInfiniteQueryKey(options), - }, - ); +export const listSnapshotFilesInfiniteOptions = (options: Options) => infiniteQueryOptions, QueryKey>, string | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( +// @ts-ignore +{ + queryFn: async ({ pageParam, queryKey, signal }) => { + // @ts-ignore + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { + query: { + offset: pageParam + } + }; + const params = createInfiniteParams(queryKey, page); + const { data } = await listSnapshotFiles({ + ...options, + ...params, + signal, + throwOnError: true + }); + return data; + }, + queryKey: listSnapshotFilesInfiniteQueryKey(options) +}); -export const dumpSnapshotQueryKey = (options: Options) => createQueryKey("dumpSnapshot", options); +export const dumpSnapshotQueryKey = (options: Options) => createQueryKey('dumpSnapshot', options); /** * Download a snapshot path as a tar archive (folders) or raw file stream (single files) */ -export const dumpSnapshotOptions = (options: Options) => - queryOptions>({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await dumpSnapshot({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: dumpSnapshotQueryKey(options), - }); +export const dumpSnapshotOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await dumpSnapshot({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: dumpSnapshotQueryKey(options) +}); /** * Restore a snapshot to a target path on the filesystem */ -export const restoreSnapshotMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions> = { - mutationFn: async (fnOptions) => { - const { data } = await restoreSnapshot({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const restoreSnapshotMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await restoreSnapshot({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; /** * Cancel a running doctor operation on a repository */ -export const cancelDoctorMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions> = { - mutationFn: async (fnOptions) => { - const { data } = await cancelDoctor({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const cancelDoctorMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await cancelDoctor({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; /** * Start an asynchronous doctor operation on a repository to fix common issues (unlock, check, repair index). The operation runs in the background and sends results via SSE events. */ -export const startDoctorMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions> = { - mutationFn: async (fnOptions) => { - const { data } = await startDoctor({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const startDoctorMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await startDoctor({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; /** * Unlock a repository by removing all stale locks */ -export const unlockRepositoryMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions> = { - mutationFn: async (fnOptions) => { - const { data } = await unlockRepository({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const unlockRepositoryMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await unlockRepository({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; /** * Tag multiple snapshots in a repository */ -export const tagSnapshotsMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions> = { - mutationFn: async (fnOptions) => { - const { data } = await tagSnapshots({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const tagSnapshotsMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await tagSnapshots({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; /** * Execute a restic command against a repository (dev panel only) */ -export const devPanelExecMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions> = { - mutationFn: async (fnOptions) => { - const { data } = await devPanelExec({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const devPanelExecMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await devPanelExec({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; -export const listBackupSchedulesQueryKey = (options?: Options) => - createQueryKey("listBackupSchedules", options); +export const listBackupSchedulesQueryKey = (options?: Options) => createQueryKey('listBackupSchedules', options); /** * List all backup schedules */ -export const listBackupSchedulesOptions = (options?: Options) => - queryOptions< - ListBackupSchedulesResponse, - DefaultError, - ListBackupSchedulesResponse, - ReturnType - >({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await listBackupSchedules({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: listBackupSchedulesQueryKey(options), - }); +export const listBackupSchedulesOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await listBackupSchedules({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: listBackupSchedulesQueryKey(options) +}); /** * Create a new backup schedule for a volume */ -export const createBackupScheduleMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions< - CreateBackupScheduleResponse, - DefaultError, - Options - > = { - mutationFn: async (fnOptions) => { - const { data } = await createBackupSchedule({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const createBackupScheduleMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await createBackupSchedule({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; /** * Delete a backup schedule */ -export const deleteBackupScheduleMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions< - DeleteBackupScheduleResponse, - DefaultError, - Options - > = { - mutationFn: async (fnOptions) => { - const { data } = await deleteBackupSchedule({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const deleteBackupScheduleMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await deleteBackupSchedule({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; -export const getBackupScheduleQueryKey = (options: Options) => - createQueryKey("getBackupSchedule", options); +export const getBackupScheduleQueryKey = (options: Options) => createQueryKey('getBackupSchedule', options); /** * Get a backup schedule by ID */ -export const getBackupScheduleOptions = (options: Options) => - queryOptions< - GetBackupScheduleResponse, - DefaultError, - GetBackupScheduleResponse, - ReturnType - >({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await getBackupSchedule({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: getBackupScheduleQueryKey(options), - }); +export const getBackupScheduleOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getBackupSchedule({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getBackupScheduleQueryKey(options) +}); /** * Update a backup schedule */ -export const updateBackupScheduleMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions< - UpdateBackupScheduleResponse, - DefaultError, - Options - > = { - mutationFn: async (fnOptions) => { - const { data } = await updateBackupSchedule({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const updateBackupScheduleMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await updateBackupSchedule({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; -export const getBackupScheduleForVolumeQueryKey = (options: Options) => - createQueryKey("getBackupScheduleForVolume", options); +export const getBackupScheduleForVolumeQueryKey = (options: Options) => createQueryKey('getBackupScheduleForVolume', options); /** * Get a backup schedule for a specific volume */ -export const getBackupScheduleForVolumeOptions = (options: Options) => - queryOptions< - GetBackupScheduleForVolumeResponse, - DefaultError, - GetBackupScheduleForVolumeResponse, - ReturnType - >({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await getBackupScheduleForVolume({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: getBackupScheduleForVolumeQueryKey(options), - }); +export const getBackupScheduleForVolumeOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getBackupScheduleForVolume({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getBackupScheduleForVolumeQueryKey(options) +}); /** * Trigger a backup immediately for a schedule */ -export const runBackupNowMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions> = { - mutationFn: async (fnOptions) => { - const { data } = await runBackupNow({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const runBackupNowMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await runBackupNow({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; /** * Stop a backup that is currently in progress */ -export const stopBackupMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions> = { - mutationFn: async (fnOptions) => { - const { data } = await stopBackup({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const stopBackupMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await stopBackup({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; /** * Manually apply retention policy to clean up old snapshots */ -export const runForgetMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions> = { - mutationFn: async (fnOptions) => { - const { data } = await runForget({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const runForgetMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await runForget({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; -export const getScheduleNotificationsQueryKey = (options: Options) => - createQueryKey("getScheduleNotifications", options); +export const getScheduleNotificationsQueryKey = (options: Options) => createQueryKey('getScheduleNotifications', options); /** * Get notification assignments for a backup schedule */ -export const getScheduleNotificationsOptions = (options: Options) => - queryOptions< - GetScheduleNotificationsResponse, - DefaultError, - GetScheduleNotificationsResponse, - ReturnType - >({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await getScheduleNotifications({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: getScheduleNotificationsQueryKey(options), - }); +export const getScheduleNotificationsOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getScheduleNotifications({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getScheduleNotificationsQueryKey(options) +}); /** * Update notification assignments for a backup schedule */ -export const updateScheduleNotificationsMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions< - UpdateScheduleNotificationsResponse, - DefaultError, - Options - > = { - mutationFn: async (fnOptions) => { - const { data } = await updateScheduleNotifications({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const updateScheduleNotificationsMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await updateScheduleNotifications({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; -export const getScheduleMirrorsQueryKey = (options: Options) => - createQueryKey("getScheduleMirrors", options); +export const getScheduleMirrorsQueryKey = (options: Options) => createQueryKey('getScheduleMirrors', options); /** * Get mirror repository assignments for a backup schedule */ -export const getScheduleMirrorsOptions = (options: Options) => - queryOptions< - GetScheduleMirrorsResponse, - DefaultError, - GetScheduleMirrorsResponse, - ReturnType - >({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await getScheduleMirrors({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: getScheduleMirrorsQueryKey(options), - }); +export const getScheduleMirrorsOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getScheduleMirrors({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getScheduleMirrorsQueryKey(options) +}); /** * Update mirror repository assignments for a backup schedule */ -export const updateScheduleMirrorsMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions< - UpdateScheduleMirrorsResponse, - DefaultError, - Options - > = { - mutationFn: async (fnOptions) => { - const { data } = await updateScheduleMirrors({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const updateScheduleMirrorsMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await updateScheduleMirrors({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; -export const getMirrorCompatibilityQueryKey = (options: Options) => - createQueryKey("getMirrorCompatibility", options); +export const getMirrorCompatibilityQueryKey = (options: Options) => createQueryKey('getMirrorCompatibility', options); /** * Get mirror compatibility info for all repositories relative to a backup schedule's primary repository */ -export const getMirrorCompatibilityOptions = (options: Options) => - queryOptions< - GetMirrorCompatibilityResponse, - DefaultError, - GetMirrorCompatibilityResponse, - ReturnType - >({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await getMirrorCompatibility({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: getMirrorCompatibilityQueryKey(options), - }); +export const getMirrorCompatibilityOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getMirrorCompatibility({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getMirrorCompatibilityQueryKey(options) +}); /** * Reorder backup schedules by providing an array of schedule short IDs in the desired order */ -export const reorderBackupSchedulesMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions< - ReorderBackupSchedulesResponse, - DefaultError, - Options - > = { - mutationFn: async (fnOptions) => { - const { data } = await reorderBackupSchedules({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const reorderBackupSchedulesMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await reorderBackupSchedules({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; -export const listNotificationDestinationsQueryKey = (options?: Options) => - createQueryKey("listNotificationDestinations", options); +export const listNotificationDestinationsQueryKey = (options?: Options) => createQueryKey('listNotificationDestinations', options); /** * List all notification destinations */ -export const listNotificationDestinationsOptions = (options?: Options) => - queryOptions< - ListNotificationDestinationsResponse, - DefaultError, - ListNotificationDestinationsResponse, - ReturnType - >({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await listNotificationDestinations({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: listNotificationDestinationsQueryKey(options), - }); +export const listNotificationDestinationsOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await listNotificationDestinations({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: listNotificationDestinationsQueryKey(options) +}); /** * Create a new notification destination */ -export const createNotificationDestinationMutation = ( - options?: Partial>, -): UseMutationOptions< - CreateNotificationDestinationResponse, - DefaultError, - Options -> => { - const mutationOptions: UseMutationOptions< - CreateNotificationDestinationResponse, - DefaultError, - Options - > = { - mutationFn: async (fnOptions) => { - const { data } = await createNotificationDestination({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const createNotificationDestinationMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await createNotificationDestination({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; /** * Delete a notification destination */ -export const deleteNotificationDestinationMutation = ( - options?: Partial>, -): UseMutationOptions< - DeleteNotificationDestinationResponse, - DefaultError, - Options -> => { - const mutationOptions: UseMutationOptions< - DeleteNotificationDestinationResponse, - DefaultError, - Options - > = { - mutationFn: async (fnOptions) => { - const { data } = await deleteNotificationDestination({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const deleteNotificationDestinationMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await deleteNotificationDestination({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; -export const getNotificationDestinationQueryKey = (options: Options) => - createQueryKey("getNotificationDestination", options); +export const getNotificationDestinationQueryKey = (options: Options) => createQueryKey('getNotificationDestination', options); /** * Get a notification destination by ID */ -export const getNotificationDestinationOptions = (options: Options) => - queryOptions< - GetNotificationDestinationResponse, - DefaultError, - GetNotificationDestinationResponse, - ReturnType - >({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await getNotificationDestination({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: getNotificationDestinationQueryKey(options), - }); +export const getNotificationDestinationOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getNotificationDestination({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getNotificationDestinationQueryKey(options) +}); /** * Update a notification destination */ -export const updateNotificationDestinationMutation = ( - options?: Partial>, -): UseMutationOptions< - UpdateNotificationDestinationResponse, - DefaultError, - Options -> => { - const mutationOptions: UseMutationOptions< - UpdateNotificationDestinationResponse, - DefaultError, - Options - > = { - mutationFn: async (fnOptions) => { - const { data } = await updateNotificationDestination({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const updateNotificationDestinationMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await updateNotificationDestination({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; /** * Test a notification destination by sending a test message */ -export const testNotificationDestinationMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions< - TestNotificationDestinationResponse, - DefaultError, - Options - > = { - mutationFn: async (fnOptions) => { - const { data } = await testNotificationDestination({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const testNotificationDestinationMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await testNotificationDestination({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; -export const getSystemInfoQueryKey = (options?: Options) => createQueryKey("getSystemInfo", options); +export const getSystemInfoQueryKey = (options?: Options) => createQueryKey('getSystemInfo', options); /** * Get system information including available capabilities */ -export const getSystemInfoOptions = (options?: Options) => - queryOptions>({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await getSystemInfo({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: getSystemInfoQueryKey(options), - }); +export const getSystemInfoOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getSystemInfo({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getSystemInfoQueryKey(options) +}); -export const getUpdatesQueryKey = (options?: Options) => createQueryKey("getUpdates", options); +export const getUpdatesQueryKey = (options?: Options) => createQueryKey('getUpdates', options); /** * Check for application updates from GitHub */ -export const getUpdatesOptions = (options?: Options) => - queryOptions>({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await getUpdates({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: getUpdatesQueryKey(options), - }); +export const getUpdatesOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getUpdates({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getUpdatesQueryKey(options) +}); -export const getRegistrationStatusQueryKey = (options?: Options) => - createQueryKey("getRegistrationStatus", options); +export const getRegistrationStatusQueryKey = (options?: Options) => createQueryKey('getRegistrationStatus', options); /** * Get the current registration status for new users */ -export const getRegistrationStatusOptions = (options?: Options) => - queryOptions< - GetRegistrationStatusResponse, - DefaultError, - GetRegistrationStatusResponse, - ReturnType - >({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await getRegistrationStatus({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: getRegistrationStatusQueryKey(options), - }); +export const getRegistrationStatusOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getRegistrationStatus({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getRegistrationStatusQueryKey(options) +}); /** * Update the registration status for new users. Requires global admin role. */ -export const setRegistrationStatusMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions< - SetRegistrationStatusResponse, - DefaultError, - Options - > = { - mutationFn: async (fnOptions) => { - const { data } = await setRegistrationStatus({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const setRegistrationStatusMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await setRegistrationStatus({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; /** * Download the organization's Restic password for backup recovery. Requires organization owner or admin role and password re-authentication. */ -export const downloadResticPasswordMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions< - DownloadResticPasswordResponse, - DefaultError, - Options - > = { - mutationFn: async (fnOptions) => { - const { data } = await downloadResticPassword({ - ...options, - ...fnOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; +export const downloadResticPasswordMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await downloadResticPassword({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; }; -export const getDevPanelQueryKey = (options?: Options) => createQueryKey("getDevPanel", options); +export const getDevPanelQueryKey = (options?: Options) => createQueryKey('getDevPanel', options); /** * Get the dev panel status */ -export const getDevPanelOptions = (options?: Options) => - queryOptions>({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await getDevPanel({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: getDevPanelQueryKey(options), - }); +export const getDevPanelOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getDevPanel({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getDevPanelQueryKey(options) +}); diff --git a/app/client/api-client/client/client.gen.ts b/app/client/api-client/client/client.gen.ts index 45d0a64b..d2e55a14 100644 --- a/app/client/api-client/client/client.gen.ts +++ b/app/client/api-client/client/client.gen.ts @@ -1,285 +1,288 @@ // This file is auto-generated by @hey-api/openapi-ts -import { createSseClient } from "../core/serverSentEvents.gen"; -import type { HttpMethod } from "../core/types.gen"; -import { getValidRequestBody } from "../core/utils.gen"; -import type { Client, Config, RequestOptions, ResolvedRequestOptions } from "./types.gen"; +import { createSseClient } from '../core/serverSentEvents.gen'; +import type { HttpMethod } from '../core/types.gen'; +import { getValidRequestBody } from '../core/utils.gen'; +import type { Client, Config, RequestOptions, ResolvedRequestOptions } from './types.gen'; import { - buildUrl, - createConfig, - createInterceptors, - getParseAs, - mergeConfigs, - mergeHeaders, - setAuthParams, -} from "./utils.gen"; + buildUrl, + createConfig, + createInterceptors, + getParseAs, + mergeConfigs, + mergeHeaders, + setAuthParams, +} from './utils.gen'; -type ReqInit = Omit & { - body?: any; - headers: ReturnType; +type ReqInit = Omit & { + body?: any; + headers: ReturnType; }; export const createClient = (config: Config = {}): Client => { - let _config = mergeConfigs(createConfig(), config); + let _config = mergeConfigs(createConfig(), config); - const getConfig = (): Config => ({ ..._config }); + const getConfig = (): Config => ({ ..._config }); - const setConfig = (config: Config): Config => { - _config = mergeConfigs(_config, config); - return getConfig(); - }; + const setConfig = (config: Config): Config => { + _config = mergeConfigs(_config, config); + return getConfig(); + }; - const interceptors = createInterceptors(); + const interceptors = createInterceptors(); - const beforeRequest = async (options: RequestOptions) => { - const opts = { - ..._config, - ...options, - fetch: options.fetch ?? _config.fetch ?? globalThis.fetch, - headers: mergeHeaders(_config.headers, options.headers), - serializedBody: undefined, - }; + const beforeRequest = async (options: RequestOptions) => { + const opts = { + ..._config, + ...options, + fetch: options.fetch ?? _config.fetch ?? globalThis.fetch, + headers: mergeHeaders(_config.headers, options.headers), + serializedBody: undefined, + }; - if (opts.security) { - await setAuthParams({ - ...opts, - security: opts.security, - }); - } + if (opts.security) { + await setAuthParams({ + ...opts, + security: opts.security, + }); + } - if (opts.requestValidator) { - await opts.requestValidator(opts); - } + if (opts.requestValidator) { + await opts.requestValidator(opts); + } - if (opts.body !== undefined && opts.bodySerializer) { - opts.serializedBody = opts.bodySerializer(opts.body); - } + if (opts.body !== undefined && opts.bodySerializer) { + opts.serializedBody = opts.bodySerializer(opts.body); + } - // remove Content-Type header if body is empty to avoid sending invalid requests - if (opts.body === undefined || opts.serializedBody === "") { - opts.headers.delete("Content-Type"); - } + // remove Content-Type header if body is empty to avoid sending invalid requests + if (opts.body === undefined || opts.serializedBody === '') { + opts.headers.delete('Content-Type'); + } - const url = buildUrl(opts); + const url = buildUrl(opts); - return { opts, url }; - }; + return { opts, url }; + }; - const request: Client["request"] = async (options) => { - // @ts-expect-error - const { opts, url } = await beforeRequest(options); - const requestInit: ReqInit = { - redirect: "follow", - ...opts, - body: getValidRequestBody(opts), - }; + const request: Client['request'] = async (options) => { + // @ts-expect-error + const { opts, url } = await beforeRequest(options); + const requestInit: ReqInit = { + redirect: 'follow', + ...opts, + body: getValidRequestBody(opts), + }; - let request = new Request(url, requestInit); + let request = new Request(url, requestInit); - for (const fn of interceptors.request.fns) { - if (fn) { - request = await fn(request, opts); - } - } + for (const fn of interceptors.request.fns) { + if (fn) { + request = await fn(request, opts); + } + } - // fetch must be assigned here, otherwise it would throw the error: - // TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation - const _fetch = opts.fetch!; - let response: Response; + // fetch must be assigned here, otherwise it would throw the error: + // TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation + const _fetch = opts.fetch!; + let response: Response; - try { - response = await _fetch(request); - } catch (error) { - // Handle fetch exceptions (AbortError, network errors, etc.) - let finalError = error; + try { + response = await _fetch(request); + } catch (error) { + // Handle fetch exceptions (AbortError, network errors, etc.) + let finalError = error; - for (const fn of interceptors.error.fns) { - if (fn) { - finalError = (await fn(error, undefined as any, request, opts)) as unknown; - } - } + for (const fn of interceptors.error.fns) { + if (fn) { + finalError = (await fn(error, undefined as any, request, opts)) as unknown; + } + } - finalError = finalError || ({} as unknown); + finalError = finalError || ({} as unknown); - if (opts.throwOnError) { - throw finalError; - } + if (opts.throwOnError) { + throw finalError; + } - // Return error response - return opts.responseStyle === "data" - ? undefined - : { - error: finalError, - request, - response: undefined as any, - }; - } + // Return error response + return opts.responseStyle === 'data' + ? undefined + : { + error: finalError, + request, + response: undefined as any, + }; + } - for (const fn of interceptors.response.fns) { - if (fn) { - response = await fn(response, request, opts); - } - } + for (const fn of interceptors.response.fns) { + if (fn) { + response = await fn(response, request, opts); + } + } - const result = { - request, - response, - }; + const result = { + request, + response, + }; - if (response.ok) { - const parseAs = - (opts.parseAs === "auto" ? getParseAs(response.headers.get("Content-Type")) : opts.parseAs) ?? "json"; + if (response.ok) { + const parseAs = + (opts.parseAs === 'auto' + ? getParseAs(response.headers.get('Content-Type')) + : opts.parseAs) ?? 'json'; - if (response.status === 204 || response.headers.get("Content-Length") === "0") { - let emptyData: any; - switch (parseAs) { - case "arrayBuffer": - case "blob": - case "text": - emptyData = await response[parseAs](); - break; - case "formData": - emptyData = new FormData(); - break; - case "stream": - emptyData = response.body; - break; - case "json": - default: - emptyData = {}; - break; - } - return opts.responseStyle === "data" - ? emptyData - : { - data: emptyData, - ...result, - }; - } + if (response.status === 204 || response.headers.get('Content-Length') === '0') { + let emptyData: any; + switch (parseAs) { + case 'arrayBuffer': + case 'blob': + case 'text': + emptyData = await response[parseAs](); + break; + case 'formData': + emptyData = new FormData(); + break; + case 'stream': + emptyData = response.body; + break; + case 'json': + default: + emptyData = {}; + break; + } + return opts.responseStyle === 'data' + ? emptyData + : { + data: emptyData, + ...result, + }; + } - let data: any; - switch (parseAs) { - case "arrayBuffer": - case "blob": - case "formData": - case "text": - data = await response[parseAs](); - break; - case "json": { - // Some servers return 200 with no Content-Length and empty body. - // response.json() would throw; read as text and parse if non-empty. - const text = await response.text(); - data = text ? JSON.parse(text) : {}; - break; - } - case "stream": - return opts.responseStyle === "data" - ? response.body - : { - data: response.body, - ...result, - }; - } + let data: any; + switch (parseAs) { + case 'arrayBuffer': + case 'blob': + case 'formData': + case 'text': + data = await response[parseAs](); + break; + case 'json': { + // Some servers return 200 with no Content-Length and empty body. + // response.json() would throw; read as text and parse if non-empty. + const text = await response.text(); + data = text ? JSON.parse(text) : {}; + break; + } + case 'stream': + return opts.responseStyle === 'data' + ? response.body + : { + data: response.body, + ...result, + }; + } - if (parseAs === "json") { - if (opts.responseValidator) { - await opts.responseValidator(data); - } + if (parseAs === 'json') { + if (opts.responseValidator) { + await opts.responseValidator(data); + } - if (opts.responseTransformer) { - data = await opts.responseTransformer(data); - } - } + if (opts.responseTransformer) { + data = await opts.responseTransformer(data); + } + } - return opts.responseStyle === "data" - ? data - : { - data, - ...result, - }; - } + return opts.responseStyle === 'data' + ? data + : { + data, + ...result, + }; + } - const textError = await response.text(); - let jsonError: unknown; + const textError = await response.text(); + let jsonError: unknown; - try { - jsonError = JSON.parse(textError); - } catch { - // noop - } + try { + jsonError = JSON.parse(textError); + } catch { + // noop + } - const error = jsonError ?? textError; - let finalError = error; + const error = jsonError ?? textError; + let finalError = error; - for (const fn of interceptors.error.fns) { - if (fn) { - finalError = (await fn(error, response, request, opts)) as string; - } - } + for (const fn of interceptors.error.fns) { + if (fn) { + finalError = (await fn(error, response, request, opts)) as string; + } + } - finalError = finalError || ({} as string); + finalError = finalError || ({} as string); - if (opts.throwOnError) { - throw finalError; - } + if (opts.throwOnError) { + throw finalError; + } - // TODO: we probably want to return error and improve types - return opts.responseStyle === "data" - ? undefined - : { - error: finalError, - ...result, - }; - }; + // TODO: we probably want to return error and improve types + return opts.responseStyle === 'data' + ? undefined + : { + error: finalError, + ...result, + }; + }; - const makeMethodFn = (method: Uppercase) => (options: RequestOptions) => request({ ...options, method }); + const makeMethodFn = (method: Uppercase) => (options: RequestOptions) => + request({ ...options, method }); - const makeSseFn = (method: Uppercase) => async (options: RequestOptions) => { - const { opts, url } = await beforeRequest(options); - return createSseClient({ - ...opts, - body: opts.body as BodyInit | null | undefined, - headers: opts.headers as unknown as Record, - method, - onRequest: async (url, init) => { - let request = new Request(url, init); - for (const fn of interceptors.request.fns) { - if (fn) { - request = await fn(request, opts); - } - } - return request; - }, - serializedBody: getValidRequestBody(opts) as BodyInit | null | undefined, - url, - }); - }; + const makeSseFn = (method: Uppercase) => async (options: RequestOptions) => { + const { opts, url } = await beforeRequest(options); + return createSseClient({ + ...opts, + body: opts.body as BodyInit | null | undefined, + headers: opts.headers as unknown as Record, + method, + onRequest: async (url, init) => { + let request = new Request(url, init); + for (const fn of interceptors.request.fns) { + if (fn) { + request = await fn(request, opts); + } + } + return request; + }, + serializedBody: getValidRequestBody(opts) as BodyInit | null | undefined, + url, + }); + }; - return { - buildUrl, - connect: makeMethodFn("CONNECT"), - delete: makeMethodFn("DELETE"), - get: makeMethodFn("GET"), - getConfig, - head: makeMethodFn("HEAD"), - interceptors, - options: makeMethodFn("OPTIONS"), - patch: makeMethodFn("PATCH"), - post: makeMethodFn("POST"), - put: makeMethodFn("PUT"), - request, - setConfig, - sse: { - connect: makeSseFn("CONNECT"), - delete: makeSseFn("DELETE"), - get: makeSseFn("GET"), - head: makeSseFn("HEAD"), - options: makeSseFn("OPTIONS"), - patch: makeSseFn("PATCH"), - post: makeSseFn("POST"), - put: makeSseFn("PUT"), - trace: makeSseFn("TRACE"), - }, - trace: makeMethodFn("TRACE"), - } as Client; + return { + buildUrl, + connect: makeMethodFn('CONNECT'), + delete: makeMethodFn('DELETE'), + get: makeMethodFn('GET'), + getConfig, + head: makeMethodFn('HEAD'), + interceptors, + options: makeMethodFn('OPTIONS'), + patch: makeMethodFn('PATCH'), + post: makeMethodFn('POST'), + put: makeMethodFn('PUT'), + request, + setConfig, + sse: { + connect: makeSseFn('CONNECT'), + delete: makeSseFn('DELETE'), + get: makeSseFn('GET'), + head: makeSseFn('HEAD'), + options: makeSseFn('OPTIONS'), + patch: makeSseFn('PATCH'), + post: makeSseFn('POST'), + put: makeSseFn('PUT'), + trace: makeSseFn('TRACE'), + }, + trace: makeMethodFn('TRACE'), + } as Client; }; diff --git a/app/client/api-client/client/types.gen.ts b/app/client/api-client/client/types.gen.ts index b5495c11..cb6d0d54 100644 --- a/app/client/api-client/client/types.gen.ts +++ b/app/client/api-client/client/types.gen.ts @@ -1,175 +1,182 @@ // This file is auto-generated by @hey-api/openapi-ts -import type { Auth } from "../core/auth.gen"; -import type { ServerSentEventsOptions, ServerSentEventsResult } from "../core/serverSentEvents.gen"; -import type { Client as CoreClient, Config as CoreConfig } from "../core/types.gen"; -import type { Middleware } from "./utils.gen"; +import type { Auth } from '../core/auth.gen'; +import type { + ServerSentEventsOptions, + ServerSentEventsResult, +} from '../core/serverSentEvents.gen'; +import type { Client as CoreClient, Config as CoreConfig } from '../core/types.gen'; +import type { Middleware } from './utils.gen'; -export type ResponseStyle = "data" | "fields"; +export type ResponseStyle = 'data' | 'fields'; export interface Config - extends Omit, CoreConfig { - /** - * Base URL for all requests made by this client. - */ - baseUrl?: T["baseUrl"]; - /** - * Fetch API implementation. You can use this option to provide a custom - * fetch instance. - * - * @default globalThis.fetch - */ - fetch?: typeof fetch; - /** - * Please don't use the Fetch client for Next.js applications. The `next` - * options won't have any effect. - * - * Install {@link https://www.npmjs.com/package/@hey-api/client-next `@hey-api/client-next`} instead. - */ - next?: never; - /** - * Return the response data parsed in a specified format. By default, `auto` - * will infer the appropriate method from the `Content-Type` response header. - * You can override this behavior with any of the {@link Body} methods. - * Select `stream` if you don't want to parse response data at all. - * - * @default 'auto' - */ - parseAs?: "arrayBuffer" | "auto" | "blob" | "formData" | "json" | "stream" | "text"; - /** - * Should we return only data or multiple fields (data, error, response, etc.)? - * - * @default 'fields' - */ - responseStyle?: ResponseStyle; - /** - * Throw an error instead of returning it in the response? - * - * @default false - */ - throwOnError?: T["throwOnError"]; + extends Omit, CoreConfig { + /** + * Base URL for all requests made by this client. + */ + baseUrl?: T['baseUrl']; + /** + * Fetch API implementation. You can use this option to provide a custom + * fetch instance. + * + * @default globalThis.fetch + */ + fetch?: typeof fetch; + /** + * Please don't use the Fetch client for Next.js applications. The `next` + * options won't have any effect. + * + * Install {@link https://www.npmjs.com/package/@hey-api/client-next `@hey-api/client-next`} instead. + */ + next?: never; + /** + * Return the response data parsed in a specified format. By default, `auto` + * will infer the appropriate method from the `Content-Type` response header. + * You can override this behavior with any of the {@link Body} methods. + * Select `stream` if you don't want to parse response data at all. + * + * @default 'auto' + */ + parseAs?: 'arrayBuffer' | 'auto' | 'blob' | 'formData' | 'json' | 'stream' | 'text'; + /** + * Should we return only data or multiple fields (data, error, response, etc.)? + * + * @default 'fields' + */ + responseStyle?: ResponseStyle; + /** + * Throw an error instead of returning it in the response? + * + * @default false + */ + throwOnError?: T['throwOnError']; } export interface RequestOptions< - TData = unknown, - TResponseStyle extends ResponseStyle = "fields", - ThrowOnError extends boolean = boolean, - Url extends string = string, + TData = unknown, + TResponseStyle extends ResponseStyle = 'fields', + ThrowOnError extends boolean = boolean, + Url extends string = string, > - extends - Config<{ - responseStyle: TResponseStyle; - throwOnError: ThrowOnError; - }>, - Pick< - ServerSentEventsOptions, - "onSseError" | "onSseEvent" | "sseDefaultRetryDelay" | "sseMaxRetryAttempts" | "sseMaxRetryDelay" - > { - /** - * Any body that you want to add to your request. - * - * {@link https://developer.mozilla.org/docs/Web/API/fetch#body} - */ - body?: unknown; - path?: Record; - query?: Record; - /** - * Security mechanism(s) to use for the request. - */ - security?: ReadonlyArray; - url: Url; + extends + Config<{ + responseStyle: TResponseStyle; + throwOnError: ThrowOnError; + }>, + Pick< + ServerSentEventsOptions, + | 'onSseError' + | 'onSseEvent' + | 'sseDefaultRetryDelay' + | 'sseMaxRetryAttempts' + | 'sseMaxRetryDelay' + > { + /** + * Any body that you want to add to your request. + * + * {@link https://developer.mozilla.org/docs/Web/API/fetch#body} + */ + body?: unknown; + path?: Record; + query?: Record; + /** + * Security mechanism(s) to use for the request. + */ + security?: ReadonlyArray; + url: Url; } export interface ResolvedRequestOptions< - TResponseStyle extends ResponseStyle = "fields", - ThrowOnError extends boolean = boolean, - Url extends string = string, + TResponseStyle extends ResponseStyle = 'fields', + ThrowOnError extends boolean = boolean, + Url extends string = string, > extends RequestOptions { - serializedBody?: string; + serializedBody?: string; } export type RequestResult< - TData = unknown, - TError = unknown, - ThrowOnError extends boolean = boolean, - TResponseStyle extends ResponseStyle = "fields", + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = boolean, + TResponseStyle extends ResponseStyle = 'fields', > = ThrowOnError extends true - ? Promise< - TResponseStyle extends "data" - ? TData extends Record - ? TData[keyof TData] - : TData - : { - data: TData extends Record ? TData[keyof TData] : TData; - request: Request; - response: Response; - } - > - : Promise< - TResponseStyle extends "data" - ? (TData extends Record ? TData[keyof TData] : TData) | undefined - : ( - | { - data: TData extends Record ? TData[keyof TData] : TData; - error: undefined; - } - | { - data: undefined; - error: TError extends Record ? TError[keyof TError] : TError; - } - ) & { - request: Request; - response: Response; - } - >; + ? Promise< + TResponseStyle extends 'data' + ? TData extends Record + ? TData[keyof TData] + : TData + : { + data: TData extends Record ? TData[keyof TData] : TData; + request: Request; + response: Response; + } + > + : Promise< + TResponseStyle extends 'data' + ? (TData extends Record ? TData[keyof TData] : TData) | undefined + : ( + | { + data: TData extends Record ? TData[keyof TData] : TData; + error: undefined; + } + | { + data: undefined; + error: TError extends Record ? TError[keyof TError] : TError; + } + ) & { + request: Request; + response: Response; + } + >; export interface ClientOptions { - baseUrl?: string; - responseStyle?: ResponseStyle; - throwOnError?: boolean; + baseUrl?: string; + responseStyle?: ResponseStyle; + throwOnError?: boolean; } type MethodFn = < - TData = unknown, - TError = unknown, - ThrowOnError extends boolean = false, - TResponseStyle extends ResponseStyle = "fields", + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = false, + TResponseStyle extends ResponseStyle = 'fields', >( - options: Omit, "method">, + options: Omit, 'method'>, ) => RequestResult; type SseFn = < - TData = unknown, - TError = unknown, - ThrowOnError extends boolean = false, - TResponseStyle extends ResponseStyle = "fields", + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = false, + TResponseStyle extends ResponseStyle = 'fields', >( - options: Omit, "method">, + options: Omit, 'method'>, ) => Promise>; type RequestFn = < - TData = unknown, - TError = unknown, - ThrowOnError extends boolean = false, - TResponseStyle extends ResponseStyle = "fields", + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = false, + TResponseStyle extends ResponseStyle = 'fields', >( - options: Omit, "method"> & - Pick>, "method">, + options: Omit, 'method'> & + Pick>, 'method'>, ) => RequestResult; type BuildUrlFn = < - TData extends { - body?: unknown; - path?: Record; - query?: Record; - url: string; - }, + TData extends { + body?: unknown; + path?: Record; + query?: Record; + url: string; + }, >( - options: TData & Options, + options: TData & Options, ) => string; export type Client = CoreClient & { - interceptors: Middleware; + interceptors: Middleware; }; /** @@ -181,23 +188,26 @@ export type Client = CoreClient * to ensure your client always has the correct values. */ export type CreateClientConfig = ( - override?: Config, + override?: Config, ) => Config & T>; export interface TDataShape { - body?: unknown; - headers?: unknown; - path?: unknown; - query?: unknown; - url: string; + body?: unknown; + headers?: unknown; + path?: unknown; + query?: unknown; + url: string; } type OmitKeys = Pick>; export type Options< - TData extends TDataShape = TDataShape, - ThrowOnError extends boolean = boolean, - TResponse = unknown, - TResponseStyle extends ResponseStyle = "fields", -> = OmitKeys, "body" | "path" | "query" | "url"> & - ([TData] extends [never] ? unknown : Omit); + TData extends TDataShape = TDataShape, + ThrowOnError extends boolean = boolean, + TResponse = unknown, + TResponseStyle extends ResponseStyle = 'fields', +> = OmitKeys< + RequestOptions, + 'body' | 'path' | 'query' | 'url' +> & + ([TData] extends [never] ? unknown : Omit); diff --git a/app/client/api-client/client/utils.gen.ts b/app/client/api-client/client/utils.gen.ts index fb460443..b4bd2435 100644 --- a/app/client/api-client/client/utils.gen.ts +++ b/app/client/api-client/client/utils.gen.ts @@ -1,289 +1,316 @@ // This file is auto-generated by @hey-api/openapi-ts -import { getAuthToken } from "../core/auth.gen"; -import type { QuerySerializerOptions } from "../core/bodySerializer.gen"; -import { jsonBodySerializer } from "../core/bodySerializer.gen"; -import { serializeArrayParam, serializeObjectParam, serializePrimitiveParam } from "../core/pathSerializer.gen"; -import { getUrl } from "../core/utils.gen"; -import type { Client, ClientOptions, Config, RequestOptions } from "./types.gen"; +import { getAuthToken } from '../core/auth.gen'; +import type { QuerySerializerOptions } from '../core/bodySerializer.gen'; +import { jsonBodySerializer } from '../core/bodySerializer.gen'; +import { + serializeArrayParam, + serializeObjectParam, + serializePrimitiveParam, +} from '../core/pathSerializer.gen'; +import { getUrl } from '../core/utils.gen'; +import type { Client, ClientOptions, Config, RequestOptions } from './types.gen'; -export const createQuerySerializer = ({ parameters = {}, ...args }: QuerySerializerOptions = {}) => { - const querySerializer = (queryParams: T) => { - const search: string[] = []; - if (queryParams && typeof queryParams === "object") { - for (const name in queryParams) { - const value = queryParams[name]; +export const createQuerySerializer = ({ + parameters = {}, + ...args +}: QuerySerializerOptions = {}) => { + const querySerializer = (queryParams: T) => { + const search: string[] = []; + if (queryParams && typeof queryParams === 'object') { + for (const name in queryParams) { + const value = queryParams[name]; - if (value === undefined || value === null) { - continue; - } + if (value === undefined || value === null) { + continue; + } - const options = parameters[name] || args; + const options = parameters[name] || args; - if (Array.isArray(value)) { - const serializedArray = serializeArrayParam({ - allowReserved: options.allowReserved, - explode: true, - name, - style: "form", - value, - ...options.array, - }); - if (serializedArray) search.push(serializedArray); - } else if (typeof value === "object") { - const serializedObject = serializeObjectParam({ - allowReserved: options.allowReserved, - explode: true, - name, - style: "deepObject", - value: value as Record, - ...options.object, - }); - if (serializedObject) search.push(serializedObject); - } else { - const serializedPrimitive = serializePrimitiveParam({ - allowReserved: options.allowReserved, - name, - value: value as string, - }); - if (serializedPrimitive) search.push(serializedPrimitive); - } - } - } - return search.join("&"); - }; - return querySerializer; + if (Array.isArray(value)) { + const serializedArray = serializeArrayParam({ + allowReserved: options.allowReserved, + explode: true, + name, + style: 'form', + value, + ...options.array, + }); + if (serializedArray) search.push(serializedArray); + } else if (typeof value === 'object') { + const serializedObject = serializeObjectParam({ + allowReserved: options.allowReserved, + explode: true, + name, + style: 'deepObject', + value: value as Record, + ...options.object, + }); + if (serializedObject) search.push(serializedObject); + } else { + const serializedPrimitive = serializePrimitiveParam({ + allowReserved: options.allowReserved, + name, + value: value as string, + }); + if (serializedPrimitive) search.push(serializedPrimitive); + } + } + } + return search.join('&'); + }; + return querySerializer; }; /** * Infers parseAs value from provided Content-Type header. */ -export const getParseAs = (contentType: string | null): Exclude => { - if (!contentType) { - // If no Content-Type header is provided, the best we can do is return the raw response body, - // which is effectively the same as the 'stream' option. - return "stream"; - } +export const getParseAs = (contentType: string | null): Exclude => { + if (!contentType) { + // If no Content-Type header is provided, the best we can do is return the raw response body, + // which is effectively the same as the 'stream' option. + return 'stream'; + } - const cleanContent = contentType.split(";")[0]?.trim(); + const cleanContent = contentType.split(';')[0]?.trim(); - if (!cleanContent) { - return; - } + if (!cleanContent) { + return; + } - if (cleanContent.startsWith("application/json") || cleanContent.endsWith("+json")) { - return "json"; - } + if (cleanContent.startsWith('application/json') || cleanContent.endsWith('+json')) { + return 'json'; + } - if (cleanContent === "multipart/form-data") { - return "formData"; - } + if (cleanContent === 'multipart/form-data') { + return 'formData'; + } - if (["application/", "audio/", "image/", "video/"].some((type) => cleanContent.startsWith(type))) { - return "blob"; - } + if ( + ['application/', 'audio/', 'image/', 'video/'].some((type) => cleanContent.startsWith(type)) + ) { + return 'blob'; + } - if (cleanContent.startsWith("text/")) { - return "text"; - } + if (cleanContent.startsWith('text/')) { + return 'text'; + } - return; + return; }; const checkForExistence = ( - options: Pick & { - headers: Headers; - }, - name?: string, + options: Pick & { + headers: Headers; + }, + name?: string, ): boolean => { - if (!name) { - return false; - } - if (options.headers.has(name) || options.query?.[name] || options.headers.get("Cookie")?.includes(`${name}=`)) { - return true; - } - return false; + if (!name) { + return false; + } + if ( + options.headers.has(name) || + options.query?.[name] || + options.headers.get('Cookie')?.includes(`${name}=`) + ) { + return true; + } + return false; }; export const setAuthParams = async ({ - security, - ...options -}: Pick, "security"> & - Pick & { - headers: Headers; - }) => { - for (const auth of security) { - if (checkForExistence(options, auth.name)) { - continue; - } + security, + ...options +}: Pick, 'security'> & + Pick & { + headers: Headers; + }) => { + for (const auth of security) { + if (checkForExistence(options, auth.name)) { + continue; + } - const token = await getAuthToken(auth, options.auth); + const token = await getAuthToken(auth, options.auth); - if (!token) { - continue; - } + if (!token) { + continue; + } - const name = auth.name ?? "Authorization"; + const name = auth.name ?? 'Authorization'; - switch (auth.in) { - case "query": - if (!options.query) { - options.query = {}; - } - options.query[name] = token; - break; - case "cookie": - options.headers.append("Cookie", `${name}=${token}`); - break; - case "header": - default: - options.headers.set(name, token); - break; - } - } + switch (auth.in) { + case 'query': + if (!options.query) { + options.query = {}; + } + options.query[name] = token; + break; + case 'cookie': + options.headers.append('Cookie', `${name}=${token}`); + break; + case 'header': + default: + options.headers.set(name, token); + break; + } + } }; -export const buildUrl: Client["buildUrl"] = (options) => - getUrl({ - baseUrl: options.baseUrl as string, - path: options.path, - query: options.query, - querySerializer: - typeof options.querySerializer === "function" - ? options.querySerializer - : createQuerySerializer(options.querySerializer), - url: options.url, - }); +export const buildUrl: Client['buildUrl'] = (options) => + getUrl({ + baseUrl: options.baseUrl as string, + path: options.path, + query: options.query, + querySerializer: + typeof options.querySerializer === 'function' + ? options.querySerializer + : createQuerySerializer(options.querySerializer), + url: options.url, + }); export const mergeConfigs = (a: Config, b: Config): Config => { - const config = { ...a, ...b }; - if (config.baseUrl?.endsWith("/")) { - config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1); - } - config.headers = mergeHeaders(a.headers, b.headers); - return config; + const config = { ...a, ...b }; + if (config.baseUrl?.endsWith('/')) { + config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1); + } + config.headers = mergeHeaders(a.headers, b.headers); + return config; }; const headersEntries = (headers: Headers): Array<[string, string]> => { - const entries: Array<[string, string]> = []; - headers.forEach((value, key) => { - entries.push([key, value]); - }); - return entries; + const entries: Array<[string, string]> = []; + headers.forEach((value, key) => { + entries.push([key, value]); + }); + return entries; }; -export const mergeHeaders = (...headers: Array["headers"] | undefined>): Headers => { - const mergedHeaders = new Headers(); - for (const header of headers) { - if (!header) { - continue; - } +export const mergeHeaders = ( + ...headers: Array['headers'] | undefined> +): Headers => { + const mergedHeaders = new Headers(); + for (const header of headers) { + if (!header) { + continue; + } - const iterator = header instanceof Headers ? headersEntries(header) : Object.entries(header); + const iterator = header instanceof Headers ? headersEntries(header) : Object.entries(header); - for (const [key, value] of iterator) { - if (value === null) { - mergedHeaders.delete(key); - } else if (Array.isArray(value)) { - for (const v of value) { - mergedHeaders.append(key, v as string); - } - } else if (value !== undefined) { - // assume object headers are meant to be JSON stringified, i.e. their - // content value in OpenAPI specification is 'application/json' - mergedHeaders.set(key, typeof value === "object" ? JSON.stringify(value) : (value as string)); - } - } - } - return mergedHeaders; + for (const [key, value] of iterator) { + if (value === null) { + mergedHeaders.delete(key); + } else if (Array.isArray(value)) { + for (const v of value) { + mergedHeaders.append(key, v as string); + } + } else if (value !== undefined) { + // assume object headers are meant to be JSON stringified, i.e. their + // content value in OpenAPI specification is 'application/json' + mergedHeaders.set( + key, + typeof value === 'object' ? JSON.stringify(value) : (value as string), + ); + } + } + } + return mergedHeaders; }; type ErrInterceptor = ( - error: Err, - response: Res, - request: Req, - options: Options, + error: Err, + response: Res, + request: Req, + options: Options, ) => Err | Promise; type ReqInterceptor = (request: Req, options: Options) => Req | Promise; -type ResInterceptor = (response: Res, request: Req, options: Options) => Res | Promise; +type ResInterceptor = ( + response: Res, + request: Req, + options: Options, +) => Res | Promise; class Interceptors { - fns: Array = []; + fns: Array = []; - clear(): void { - this.fns = []; - } + clear(): void { + this.fns = []; + } - eject(id: number | Interceptor): void { - const index = this.getInterceptorIndex(id); - if (this.fns[index]) { - this.fns[index] = null; - } - } + eject(id: number | Interceptor): void { + const index = this.getInterceptorIndex(id); + if (this.fns[index]) { + this.fns[index] = null; + } + } - exists(id: number | Interceptor): boolean { - const index = this.getInterceptorIndex(id); - return Boolean(this.fns[index]); - } + exists(id: number | Interceptor): boolean { + const index = this.getInterceptorIndex(id); + return Boolean(this.fns[index]); + } - getInterceptorIndex(id: number | Interceptor): number { - if (typeof id === "number") { - return this.fns[id] ? id : -1; - } - return this.fns.indexOf(id); - } + getInterceptorIndex(id: number | Interceptor): number { + if (typeof id === 'number') { + return this.fns[id] ? id : -1; + } + return this.fns.indexOf(id); + } - update(id: number | Interceptor, fn: Interceptor): number | Interceptor | false { - const index = this.getInterceptorIndex(id); - if (this.fns[index]) { - this.fns[index] = fn; - return id; - } - return false; - } + update(id: number | Interceptor, fn: Interceptor): number | Interceptor | false { + const index = this.getInterceptorIndex(id); + if (this.fns[index]) { + this.fns[index] = fn; + return id; + } + return false; + } - use(fn: Interceptor): number { - this.fns.push(fn); - return this.fns.length - 1; - } + use(fn: Interceptor): number { + this.fns.push(fn); + return this.fns.length - 1; + } } export interface Middleware { - error: Interceptors>; - request: Interceptors>; - response: Interceptors>; + error: Interceptors>; + request: Interceptors>; + response: Interceptors>; } -export const createInterceptors = (): Middleware => ({ - error: new Interceptors>(), - request: new Interceptors>(), - response: new Interceptors>(), +export const createInterceptors = (): Middleware< + Req, + Res, + Err, + Options +> => ({ + error: new Interceptors>(), + request: new Interceptors>(), + response: new Interceptors>(), }); const defaultQuerySerializer = createQuerySerializer({ - allowReserved: false, - array: { - explode: true, - style: "form", - }, - object: { - explode: true, - style: "deepObject", - }, + allowReserved: false, + array: { + explode: true, + style: 'form', + }, + object: { + explode: true, + style: 'deepObject', + }, }); const defaultHeaders = { - "Content-Type": "application/json", + 'Content-Type': 'application/json', }; export const createConfig = ( - override: Config & T> = {}, + override: Config & T> = {}, ): Config & T> => ({ - ...jsonBodySerializer, - headers: defaultHeaders, - parseAs: "auto", - querySerializer: defaultQuerySerializer, - ...override, + ...jsonBodySerializer, + headers: defaultHeaders, + parseAs: 'auto', + querySerializer: defaultQuerySerializer, + ...override, }); diff --git a/app/client/api-client/core/auth.gen.ts b/app/client/api-client/core/auth.gen.ts index 9d804052..3ebf9947 100644 --- a/app/client/api-client/core/auth.gen.ts +++ b/app/client/api-client/core/auth.gen.ts @@ -3,39 +3,39 @@ export type AuthToken = string | undefined; export interface Auth { - /** - * Which part of the request do we use to send the auth? - * - * @default 'header' - */ - in?: "header" | "query" | "cookie"; - /** - * Header or query parameter name. - * - * @default 'Authorization' - */ - name?: string; - scheme?: "basic" | "bearer"; - type: "apiKey" | "http"; + /** + * Which part of the request do we use to send the auth? + * + * @default 'header' + */ + in?: 'header' | 'query' | 'cookie'; + /** + * Header or query parameter name. + * + * @default 'Authorization' + */ + name?: string; + scheme?: 'basic' | 'bearer'; + type: 'apiKey' | 'http'; } export const getAuthToken = async ( - auth: Auth, - callback: ((auth: Auth) => Promise | AuthToken) | AuthToken, + auth: Auth, + callback: ((auth: Auth) => Promise | AuthToken) | AuthToken, ): Promise => { - const token = typeof callback === "function" ? await callback(auth) : callback; + const token = typeof callback === 'function' ? await callback(auth) : callback; - if (!token) { - return; - } + if (!token) { + return; + } - if (auth.scheme === "bearer") { - return `Bearer ${token}`; - } + if (auth.scheme === 'bearer') { + return `Bearer ${token}`; + } - if (auth.scheme === "basic") { - return `Basic ${btoa(token)}`; - } + if (auth.scheme === 'basic') { + return `Basic ${btoa(token)}`; + } - return token; + return token; }; diff --git a/app/client/api-client/core/bodySerializer.gen.ts b/app/client/api-client/core/bodySerializer.gen.ts index 10e7b3a6..8ad92c9f 100644 --- a/app/client/api-client/core/bodySerializer.gen.ts +++ b/app/client/api-client/core/bodySerializer.gen.ts @@ -1,82 +1,84 @@ // This file is auto-generated by @hey-api/openapi-ts -import type { ArrayStyle, ObjectStyle, SerializerOptions } from "./pathSerializer.gen"; +import type { ArrayStyle, ObjectStyle, SerializerOptions } from './pathSerializer.gen'; export type QuerySerializer = (query: Record) => string; export type BodySerializer = (body: any) => any; type QuerySerializerOptionsObject = { - allowReserved?: boolean; - array?: Partial>; - object?: Partial>; + allowReserved?: boolean; + array?: Partial>; + object?: Partial>; }; export type QuerySerializerOptions = QuerySerializerOptionsObject & { - /** - * Per-parameter serialization overrides. When provided, these settings - * override the global array/object settings for specific parameter names. - */ - parameters?: Record; + /** + * Per-parameter serialization overrides. When provided, these settings + * override the global array/object settings for specific parameter names. + */ + parameters?: Record; }; const serializeFormDataPair = (data: FormData, key: string, value: unknown): void => { - if (typeof value === "string" || value instanceof Blob) { - data.append(key, value); - } else if (value instanceof Date) { - data.append(key, value.toISOString()); - } else { - data.append(key, JSON.stringify(value)); - } + if (typeof value === 'string' || value instanceof Blob) { + data.append(key, value); + } else if (value instanceof Date) { + data.append(key, value.toISOString()); + } else { + data.append(key, JSON.stringify(value)); + } }; const serializeUrlSearchParamsPair = (data: URLSearchParams, key: string, value: unknown): void => { - if (typeof value === "string") { - data.append(key, value); - } else { - data.append(key, JSON.stringify(value)); - } + if (typeof value === 'string') { + data.append(key, value); + } else { + data.append(key, JSON.stringify(value)); + } }; export const formDataBodySerializer = { - bodySerializer: | Array>>(body: T): FormData => { - const data = new FormData(); + bodySerializer: | Array>>( + body: T, + ): FormData => { + const data = new FormData(); - Object.entries(body).forEach(([key, value]) => { - if (value === undefined || value === null) { - return; - } - if (Array.isArray(value)) { - value.forEach((v) => serializeFormDataPair(data, key, v)); - } else { - serializeFormDataPair(data, key, value); - } - }); + Object.entries(body).forEach(([key, value]) => { + if (value === undefined || value === null) { + return; + } + if (Array.isArray(value)) { + value.forEach((v) => serializeFormDataPair(data, key, v)); + } else { + serializeFormDataPair(data, key, value); + } + }); - return data; - }, + return data; + }, }; export const jsonBodySerializer = { - bodySerializer: (body: T): string => - JSON.stringify(body, (_key, value) => (typeof value === "bigint" ? value.toString() : value)), + bodySerializer: (body: T): string => + JSON.stringify(body, (_key, value) => (typeof value === 'bigint' ? value.toString() : value)), }; export const urlSearchParamsBodySerializer = { - bodySerializer: | Array>>(body: T): string => { - const data = new URLSearchParams(); + bodySerializer: | Array>>(body: T): string => { + const data = new URLSearchParams(); - Object.entries(body).forEach(([key, value]) => { - if (value === undefined || value === null) { - return; - } - if (Array.isArray(value)) { - value.forEach((v) => serializeUrlSearchParamsPair(data, key, v)); - } else { - serializeUrlSearchParamsPair(data, key, value); - } - }); + Object.entries(body).forEach(([key, value]) => { + if (value === undefined || value === null) { + return; + } + if (Array.isArray(value)) { + value.forEach((v) => serializeUrlSearchParamsPair(data, key, v)); + } else { + serializeUrlSearchParamsPair(data, key, value); + } + }); - return data.toString(); - }, + return data.toString(); + }, }; diff --git a/app/client/api-client/core/params.gen.ts b/app/client/api-client/core/params.gen.ts index c1fb15c5..6099cab1 100644 --- a/app/client/api-client/core/params.gen.ts +++ b/app/client/api-client/core/params.gen.ts @@ -1,169 +1,169 @@ // This file is auto-generated by @hey-api/openapi-ts -type Slot = "body" | "headers" | "path" | "query"; +type Slot = 'body' | 'headers' | 'path' | 'query'; export type Field = - | { - in: Exclude; - /** - * Field name. This is the name we want the user to see and use. - */ - key: string; - /** - * Field mapped name. This is the name we want to use in the request. - * If omitted, we use the same value as `key`. - */ - map?: string; - } - | { - in: Extract; - /** - * Key isn't required for bodies. - */ - key?: string; - map?: string; - } - | { - /** - * Field name. This is the name we want the user to see and use. - */ - key: string; - /** - * Field mapped name. This is the name we want to use in the request. - * If `in` is omitted, `map` aliases `key` to the transport layer. - */ - map: Slot; - }; + | { + in: Exclude; + /** + * Field name. This is the name we want the user to see and use. + */ + key: string; + /** + * Field mapped name. This is the name we want to use in the request. + * If omitted, we use the same value as `key`. + */ + map?: string; + } + | { + in: Extract; + /** + * Key isn't required for bodies. + */ + key?: string; + map?: string; + } + | { + /** + * Field name. This is the name we want the user to see and use. + */ + key: string; + /** + * Field mapped name. This is the name we want to use in the request. + * If `in` is omitted, `map` aliases `key` to the transport layer. + */ + map: Slot; + }; export interface Fields { - allowExtra?: Partial>; - args?: ReadonlyArray; + allowExtra?: Partial>; + args?: ReadonlyArray; } export type FieldsConfig = ReadonlyArray; const extraPrefixesMap: Record = { - $body_: "body", - $headers_: "headers", - $path_: "path", - $query_: "query", + $body_: 'body', + $headers_: 'headers', + $path_: 'path', + $query_: 'query', }; const extraPrefixes = Object.entries(extraPrefixesMap); type KeyMap = Map< - string, - | { - in: Slot; - map?: string; - } - | { - in?: never; - map: Slot; - } + string, + | { + in: Slot; + map?: string; + } + | { + in?: never; + map: Slot; + } >; const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => { - if (!map) { - map = new Map(); - } + if (!map) { + map = new Map(); + } - for (const config of fields) { - if ("in" in config) { - if (config.key) { - map.set(config.key, { - in: config.in, - map: config.map, - }); - } - } else if ("key" in config) { - map.set(config.key, { - map: config.map, - }); - } else if (config.args) { - buildKeyMap(config.args, map); - } - } + for (const config of fields) { + if ('in' in config) { + if (config.key) { + map.set(config.key, { + in: config.in, + map: config.map, + }); + } + } else if ('key' in config) { + map.set(config.key, { + map: config.map, + }); + } else if (config.args) { + buildKeyMap(config.args, map); + } + } - return map; + return map; }; interface Params { - body: unknown; - headers: Record; - path: Record; - query: Record; + body: unknown; + headers: Record; + path: Record; + query: Record; } const stripEmptySlots = (params: Params) => { - for (const [slot, value] of Object.entries(params)) { - if (value && typeof value === "object" && !Object.keys(value).length) { - delete params[slot as Slot]; - } - } + for (const [slot, value] of Object.entries(params)) { + if (value && typeof value === 'object' && !Object.keys(value).length) { + delete params[slot as Slot]; + } + } }; export const buildClientParams = (args: ReadonlyArray, fields: FieldsConfig) => { - const params: Params = { - body: {}, - headers: {}, - path: {}, - query: {}, - }; + const params: Params = { + body: {}, + headers: {}, + path: {}, + query: {}, + }; - const map = buildKeyMap(fields); + const map = buildKeyMap(fields); - let config: FieldsConfig[number] | undefined; + let config: FieldsConfig[number] | undefined; - for (const [index, arg] of args.entries()) { - if (fields[index]) { - config = fields[index]; - } + for (const [index, arg] of args.entries()) { + if (fields[index]) { + config = fields[index]; + } - if (!config) { - continue; - } + if (!config) { + continue; + } - if ("in" in config) { - if (config.key) { - const field = map.get(config.key)!; - const name = field.map || config.key; - if (field.in) { - (params[field.in] as Record)[name] = arg; - } - } else { - params.body = arg; - } - } else { - for (const [key, value] of Object.entries(arg ?? {})) { - const field = map.get(key); + if ('in' in config) { + if (config.key) { + const field = map.get(config.key)!; + const name = field.map || config.key; + if (field.in) { + (params[field.in] as Record)[name] = arg; + } + } else { + params.body = arg; + } + } else { + for (const [key, value] of Object.entries(arg ?? {})) { + const field = map.get(key); - if (field) { - if (field.in) { - const name = field.map || key; - (params[field.in] as Record)[name] = value; - } else { - params[field.map] = value; - } - } else { - const extra = extraPrefixes.find(([prefix]) => key.startsWith(prefix)); + if (field) { + if (field.in) { + const name = field.map || key; + (params[field.in] as Record)[name] = value; + } else { + params[field.map] = value; + } + } else { + const extra = extraPrefixes.find(([prefix]) => key.startsWith(prefix)); - if (extra) { - const [prefix, slot] = extra; - (params[slot] as Record)[key.slice(prefix.length)] = value; - } else if ("allowExtra" in config && config.allowExtra) { - for (const [slot, allowed] of Object.entries(config.allowExtra)) { - if (allowed) { - (params[slot as Slot] as Record)[key] = value; - break; - } - } - } - } - } - } - } + if (extra) { + const [prefix, slot] = extra; + (params[slot] as Record)[key.slice(prefix.length)] = value; + } else if ('allowExtra' in config && config.allowExtra) { + for (const [slot, allowed] of Object.entries(config.allowExtra)) { + if (allowed) { + (params[slot as Slot] as Record)[key] = value; + break; + } + } + } + } + } + } + } - stripEmptySlots(params); + stripEmptySlots(params); - return params; + return params; }; diff --git a/app/client/api-client/core/pathSerializer.gen.ts b/app/client/api-client/core/pathSerializer.gen.ts index 9e3cccde..994b2848 100644 --- a/app/client/api-client/core/pathSerializer.gen.ts +++ b/app/client/api-client/core/pathSerializer.gen.ts @@ -3,165 +3,169 @@ interface SerializeOptions extends SerializePrimitiveOptions, SerializerOptions {} interface SerializePrimitiveOptions { - allowReserved?: boolean; - name: string; + allowReserved?: boolean; + name: string; } export interface SerializerOptions { - /** - * @default true - */ - explode: boolean; - style: T; + /** + * @default true + */ + explode: boolean; + style: T; } -export type ArrayStyle = "form" | "spaceDelimited" | "pipeDelimited"; +export type ArrayStyle = 'form' | 'spaceDelimited' | 'pipeDelimited'; export type ArraySeparatorStyle = ArrayStyle | MatrixStyle; -type MatrixStyle = "label" | "matrix" | "simple"; -export type ObjectStyle = "form" | "deepObject"; +type MatrixStyle = 'label' | 'matrix' | 'simple'; +export type ObjectStyle = 'form' | 'deepObject'; type ObjectSeparatorStyle = ObjectStyle | MatrixStyle; interface SerializePrimitiveParam extends SerializePrimitiveOptions { - value: string; + value: string; } export const separatorArrayExplode = (style: ArraySeparatorStyle) => { - switch (style) { - case "label": - return "."; - case "matrix": - return ";"; - case "simple": - return ","; - default: - return "&"; - } + switch (style) { + case 'label': + return '.'; + case 'matrix': + return ';'; + case 'simple': + return ','; + default: + return '&'; + } }; export const separatorArrayNoExplode = (style: ArraySeparatorStyle) => { - switch (style) { - case "form": - return ","; - case "pipeDelimited": - return "|"; - case "spaceDelimited": - return "%20"; - default: - return ","; - } + switch (style) { + case 'form': + return ','; + case 'pipeDelimited': + return '|'; + case 'spaceDelimited': + return '%20'; + default: + return ','; + } }; export const separatorObjectExplode = (style: ObjectSeparatorStyle) => { - switch (style) { - case "label": - return "."; - case "matrix": - return ";"; - case "simple": - return ","; - default: - return "&"; - } + switch (style) { + case 'label': + return '.'; + case 'matrix': + return ';'; + case 'simple': + return ','; + default: + return '&'; + } }; export const serializeArrayParam = ({ - allowReserved, - explode, - name, - style, - value, + allowReserved, + explode, + name, + style, + value, }: SerializeOptions & { - value: unknown[]; + value: unknown[]; }) => { - if (!explode) { - const joinedValues = (allowReserved ? value : value.map((v) => encodeURIComponent(v as string))).join( - separatorArrayNoExplode(style), - ); - switch (style) { - case "label": - return `.${joinedValues}`; - case "matrix": - return `;${name}=${joinedValues}`; - case "simple": - return joinedValues; - default: - return `${name}=${joinedValues}`; - } - } + if (!explode) { + const joinedValues = ( + allowReserved ? value : value.map((v) => encodeURIComponent(v as string)) + ).join(separatorArrayNoExplode(style)); + switch (style) { + case 'label': + return `.${joinedValues}`; + case 'matrix': + return `;${name}=${joinedValues}`; + case 'simple': + return joinedValues; + default: + return `${name}=${joinedValues}`; + } + } - const separator = separatorArrayExplode(style); - const joinedValues = value - .map((v) => { - if (style === "label" || style === "simple") { - return allowReserved ? v : encodeURIComponent(v as string); - } + const separator = separatorArrayExplode(style); + const joinedValues = value + .map((v) => { + if (style === 'label' || style === 'simple') { + return allowReserved ? v : encodeURIComponent(v as string); + } - return serializePrimitiveParam({ - allowReserved, - name, - value: v as string, - }); - }) - .join(separator); - return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues; + return serializePrimitiveParam({ + allowReserved, + name, + value: v as string, + }); + }) + .join(separator); + return style === 'label' || style === 'matrix' ? separator + joinedValues : joinedValues; }; -export const serializePrimitiveParam = ({ allowReserved, name, value }: SerializePrimitiveParam) => { - if (value === undefined || value === null) { - return ""; - } +export const serializePrimitiveParam = ({ + allowReserved, + name, + value, +}: SerializePrimitiveParam) => { + if (value === undefined || value === null) { + return ''; + } - if (typeof value === "object") { - throw new Error( - "Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.", - ); - } + if (typeof value === 'object') { + throw new Error( + 'Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.', + ); + } - return `${name}=${allowReserved ? value : encodeURIComponent(value)}`; + return `${name}=${allowReserved ? value : encodeURIComponent(value)}`; }; export const serializeObjectParam = ({ - allowReserved, - explode, - name, - style, - value, - valueOnly, + allowReserved, + explode, + name, + style, + value, + valueOnly, }: SerializeOptions & { - value: Record | Date; - valueOnly?: boolean; + value: Record | Date; + valueOnly?: boolean; }) => { - if (value instanceof Date) { - return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`; - } + if (value instanceof Date) { + return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`; + } - if (style !== "deepObject" && !explode) { - let values: string[] = []; - Object.entries(value).forEach(([key, v]) => { - values = [...values, key, allowReserved ? (v as string) : encodeURIComponent(v as string)]; - }); - const joinedValues = values.join(","); - switch (style) { - case "form": - return `${name}=${joinedValues}`; - case "label": - return `.${joinedValues}`; - case "matrix": - return `;${name}=${joinedValues}`; - default: - return joinedValues; - } - } + if (style !== 'deepObject' && !explode) { + let values: string[] = []; + Object.entries(value).forEach(([key, v]) => { + values = [...values, key, allowReserved ? (v as string) : encodeURIComponent(v as string)]; + }); + const joinedValues = values.join(','); + switch (style) { + case 'form': + return `${name}=${joinedValues}`; + case 'label': + return `.${joinedValues}`; + case 'matrix': + return `;${name}=${joinedValues}`; + default: + return joinedValues; + } + } - const separator = separatorObjectExplode(style); - const joinedValues = Object.entries(value) - .map(([key, v]) => - serializePrimitiveParam({ - allowReserved, - name: style === "deepObject" ? `${name}[${key}]` : key, - value: v as string, - }), - ) - .join(separator); - return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues; + const separator = separatorObjectExplode(style); + const joinedValues = Object.entries(value) + .map(([key, v]) => + serializePrimitiveParam({ + allowReserved, + name: style === 'deepObject' ? `${name}[${key}]` : key, + value: v as string, + }), + ) + .join(separator); + return style === 'label' || style === 'matrix' ? separator + joinedValues : joinedValues; }; diff --git a/app/client/api-client/core/queryKeySerializer.gen.ts b/app/client/api-client/core/queryKeySerializer.gen.ts index b3e87676..5000df60 100644 --- a/app/client/api-client/core/queryKeySerializer.gen.ts +++ b/app/client/api-client/core/queryKeySerializer.gen.ts @@ -3,109 +3,115 @@ /** * JSON-friendly union that mirrors what Pinia Colada can hash. */ -export type JsonValue = null | string | number | boolean | JsonValue[] | { [key: string]: JsonValue }; +export type JsonValue = + | null + | string + | number + | boolean + | JsonValue[] + | { [key: string]: JsonValue }; /** * Replacer that converts non-JSON values (bigint, Date, etc.) to safe substitutes. */ export const queryKeyJsonReplacer = (_key: string, value: unknown) => { - if (value === undefined || typeof value === "function" || typeof value === "symbol") { - return undefined; - } - if (typeof value === "bigint") { - return value.toString(); - } - if (value instanceof Date) { - return value.toISOString(); - } - return value; + if (value === undefined || typeof value === 'function' || typeof value === 'symbol') { + return undefined; + } + if (typeof value === 'bigint') { + return value.toString(); + } + if (value instanceof Date) { + return value.toISOString(); + } + return value; }; /** * Safely stringifies a value and parses it back into a JsonValue. */ export const stringifyToJsonValue = (input: unknown): JsonValue | undefined => { - try { - const json = JSON.stringify(input, queryKeyJsonReplacer); - if (json === undefined) { - return undefined; - } - return JSON.parse(json) as JsonValue; - } catch { - return undefined; - } + try { + const json = JSON.stringify(input, queryKeyJsonReplacer); + if (json === undefined) { + return undefined; + } + return JSON.parse(json) as JsonValue; + } catch { + return undefined; + } }; /** * Detects plain objects (including objects with a null prototype). */ const isPlainObject = (value: unknown): value is Record => { - if (value === null || typeof value !== "object") { - return false; - } - const prototype = Object.getPrototypeOf(value as object); - return prototype === Object.prototype || prototype === null; + if (value === null || typeof value !== 'object') { + return false; + } + const prototype = Object.getPrototypeOf(value as object); + return prototype === Object.prototype || prototype === null; }; /** * Turns URLSearchParams into a sorted JSON object for deterministic keys. */ const serializeSearchParams = (params: URLSearchParams): JsonValue => { - const entries = Array.from(params.entries()).sort(([a], [b]) => a.localeCompare(b)); - const result: Record = {}; + const entries = Array.from(params.entries()).sort(([a], [b]) => a.localeCompare(b)); + const result: Record = {}; - for (const [key, value] of entries) { - const existing = result[key]; - if (existing === undefined) { - result[key] = value; - continue; - } + for (const [key, value] of entries) { + const existing = result[key]; + if (existing === undefined) { + result[key] = value; + continue; + } - if (Array.isArray(existing)) { - (existing as string[]).push(value); - } else { - result[key] = [existing, value]; - } - } + if (Array.isArray(existing)) { + (existing as string[]).push(value); + } else { + result[key] = [existing, value]; + } + } - return result; + return result; }; /** * Normalizes any accepted value into a JSON-friendly shape for query keys. */ export const serializeQueryKeyValue = (value: unknown): JsonValue | undefined => { - if (value === null) { - return null; - } + if (value === null) { + return null; + } - if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { - return value; - } + if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { + return value; + } - if (value === undefined || typeof value === "function" || typeof value === "symbol") { - return undefined; - } + if (value === undefined || typeof value === 'function' || typeof value === 'symbol') { + return undefined; + } - if (typeof value === "bigint") { - return value.toString(); - } + if (typeof value === 'bigint') { + return value.toString(); + } - if (value instanceof Date) { - return value.toISOString(); - } + if (value instanceof Date) { + return value.toISOString(); + } - if (Array.isArray(value)) { - return stringifyToJsonValue(value); - } + if (Array.isArray(value)) { + return stringifyToJsonValue(value); + } - if (typeof URLSearchParams !== "undefined" && value instanceof URLSearchParams) { - return serializeSearchParams(value); - } + if (typeof URLSearchParams !== 'undefined' && value instanceof URLSearchParams) { + return serializeSearchParams(value); + } - if (isPlainObject(value)) { - return stringifyToJsonValue(value); - } + if (isPlainObject(value)) { + return stringifyToJsonValue(value); + } - return undefined; + return undefined; }; diff --git a/app/client/api-client/core/serverSentEvents.gen.ts b/app/client/api-client/core/serverSentEvents.gen.ts index 479546e8..6aa6cf02 100644 --- a/app/client/api-client/core/serverSentEvents.gen.ts +++ b/app/client/api-client/core/serverSentEvents.gen.ts @@ -1,239 +1,243 @@ // This file is auto-generated by @hey-api/openapi-ts -import type { Config } from "./types.gen"; +import type { Config } from './types.gen'; -export type ServerSentEventsOptions = Omit & - Pick & { - /** - * Fetch API implementation. You can use this option to provide a custom - * fetch instance. - * - * @default globalThis.fetch - */ - fetch?: typeof fetch; - /** - * Implementing clients can call request interceptors inside this hook. - */ - onRequest?: (url: string, init: RequestInit) => Promise; - /** - * Callback invoked when a network or parsing error occurs during streaming. - * - * This option applies only if the endpoint returns a stream of events. - * - * @param error The error that occurred. - */ - onSseError?: (error: unknown) => void; - /** - * Callback invoked when an event is streamed from the server. - * - * This option applies only if the endpoint returns a stream of events. - * - * @param event Event streamed from the server. - * @returns Nothing (void). - */ - onSseEvent?: (event: StreamEvent) => void; - serializedBody?: RequestInit["body"]; - /** - * Default retry delay in milliseconds. - * - * This option applies only if the endpoint returns a stream of events. - * - * @default 3000 - */ - sseDefaultRetryDelay?: number; - /** - * Maximum number of retry attempts before giving up. - */ - sseMaxRetryAttempts?: number; - /** - * Maximum retry delay in milliseconds. - * - * Applies only when exponential backoff is used. - * - * This option applies only if the endpoint returns a stream of events. - * - * @default 30000 - */ - sseMaxRetryDelay?: number; - /** - * Optional sleep function for retry backoff. - * - * Defaults to using `setTimeout`. - */ - sseSleepFn?: (ms: number) => Promise; - url: string; - }; +export type ServerSentEventsOptions = Omit & + Pick & { + /** + * Fetch API implementation. You can use this option to provide a custom + * fetch instance. + * + * @default globalThis.fetch + */ + fetch?: typeof fetch; + /** + * Implementing clients can call request interceptors inside this hook. + */ + onRequest?: (url: string, init: RequestInit) => Promise; + /** + * Callback invoked when a network or parsing error occurs during streaming. + * + * This option applies only if the endpoint returns a stream of events. + * + * @param error The error that occurred. + */ + onSseError?: (error: unknown) => void; + /** + * Callback invoked when an event is streamed from the server. + * + * This option applies only if the endpoint returns a stream of events. + * + * @param event Event streamed from the server. + * @returns Nothing (void). + */ + onSseEvent?: (event: StreamEvent) => void; + serializedBody?: RequestInit['body']; + /** + * Default retry delay in milliseconds. + * + * This option applies only if the endpoint returns a stream of events. + * + * @default 3000 + */ + sseDefaultRetryDelay?: number; + /** + * Maximum number of retry attempts before giving up. + */ + sseMaxRetryAttempts?: number; + /** + * Maximum retry delay in milliseconds. + * + * Applies only when exponential backoff is used. + * + * This option applies only if the endpoint returns a stream of events. + * + * @default 30000 + */ + sseMaxRetryDelay?: number; + /** + * Optional sleep function for retry backoff. + * + * Defaults to using `setTimeout`. + */ + sseSleepFn?: (ms: number) => Promise; + url: string; + }; export interface StreamEvent { - data: TData; - event?: string; - id?: string; - retry?: number; + data: TData; + event?: string; + id?: string; + retry?: number; } export type ServerSentEventsResult = { - stream: AsyncGenerator ? TData[keyof TData] : TData, TReturn, TNext>; + stream: AsyncGenerator< + TData extends Record ? TData[keyof TData] : TData, + TReturn, + TNext + >; }; export const createSseClient = ({ - onRequest, - onSseError, - onSseEvent, - responseTransformer, - responseValidator, - sseDefaultRetryDelay, - sseMaxRetryAttempts, - sseMaxRetryDelay, - sseSleepFn, - url, - ...options + onRequest, + onSseError, + onSseEvent, + responseTransformer, + responseValidator, + sseDefaultRetryDelay, + sseMaxRetryAttempts, + sseMaxRetryDelay, + sseSleepFn, + url, + ...options }: ServerSentEventsOptions): ServerSentEventsResult => { - let lastEventId: string | undefined; + let lastEventId: string | undefined; - const sleep = sseSleepFn ?? ((ms: number) => new Promise((resolve) => setTimeout(resolve, ms))); + const sleep = sseSleepFn ?? ((ms: number) => new Promise((resolve) => setTimeout(resolve, ms))); - const createStream = async function* () { - let retryDelay: number = sseDefaultRetryDelay ?? 3000; - let attempt = 0; - const signal = options.signal ?? new AbortController().signal; + const createStream = async function* () { + let retryDelay: number = sseDefaultRetryDelay ?? 3000; + let attempt = 0; + const signal = options.signal ?? new AbortController().signal; - while (true) { - if (signal.aborted) break; + while (true) { + if (signal.aborted) break; - attempt++; + attempt++; - const headers = - options.headers instanceof Headers - ? options.headers - : new Headers(options.headers as Record | undefined); + const headers = + options.headers instanceof Headers + ? options.headers + : new Headers(options.headers as Record | undefined); - if (lastEventId !== undefined) { - headers.set("Last-Event-ID", lastEventId); - } + if (lastEventId !== undefined) { + headers.set('Last-Event-ID', lastEventId); + } - try { - const requestInit: RequestInit = { - redirect: "follow", - ...options, - body: options.serializedBody, - headers, - signal, - }; - let request = new Request(url, requestInit); - if (onRequest) { - request = await onRequest(url, requestInit); - } - // fetch must be assigned here, otherwise it would throw the error: - // TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation - const _fetch = options.fetch ?? globalThis.fetch; - const response = await _fetch(request); + try { + const requestInit: RequestInit = { + redirect: 'follow', + ...options, + body: options.serializedBody, + headers, + signal, + }; + let request = new Request(url, requestInit); + if (onRequest) { + request = await onRequest(url, requestInit); + } + // fetch must be assigned here, otherwise it would throw the error: + // TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation + const _fetch = options.fetch ?? globalThis.fetch; + const response = await _fetch(request); - if (!response.ok) throw new Error(`SSE failed: ${response.status} ${response.statusText}`); + if (!response.ok) throw new Error(`SSE failed: ${response.status} ${response.statusText}`); - if (!response.body) throw new Error("No body in SSE response"); + if (!response.body) throw new Error('No body in SSE response'); - const reader = response.body.pipeThrough(new TextDecoderStream()).getReader(); + const reader = response.body.pipeThrough(new TextDecoderStream()).getReader(); - let buffer = ""; + let buffer = ''; - const abortHandler = () => { - try { - reader.cancel(); - } catch { - // noop - } - }; + const abortHandler = () => { + try { + reader.cancel(); + } catch { + // noop + } + }; - signal.addEventListener("abort", abortHandler); + signal.addEventListener('abort', abortHandler); - try { - while (true) { - const { done, value } = await reader.read(); - if (done) break; - buffer += value; - // Normalize line endings: CRLF -> LF, then CR -> LF - buffer = buffer.replace(/\r\n/g, "\n").replace(/\r/g, "\n"); + try { + while (true) { + const { done, value } = await reader.read(); + if (done) break; + buffer += value; + // Normalize line endings: CRLF -> LF, then CR -> LF + buffer = buffer.replace(/\r\n/g, '\n').replace(/\r/g, '\n'); - const chunks = buffer.split("\n\n"); - buffer = chunks.pop() ?? ""; + const chunks = buffer.split('\n\n'); + buffer = chunks.pop() ?? ''; - for (const chunk of chunks) { - const lines = chunk.split("\n"); - const dataLines: Array = []; - let eventName: string | undefined; + for (const chunk of chunks) { + const lines = chunk.split('\n'); + const dataLines: Array = []; + let eventName: string | undefined; - for (const line of lines) { - if (line.startsWith("data:")) { - dataLines.push(line.replace(/^data:\s*/, "")); - } else if (line.startsWith("event:")) { - eventName = line.replace(/^event:\s*/, ""); - } else if (line.startsWith("id:")) { - lastEventId = line.replace(/^id:\s*/, ""); - } else if (line.startsWith("retry:")) { - const parsed = Number.parseInt(line.replace(/^retry:\s*/, ""), 10); - if (!Number.isNaN(parsed)) { - retryDelay = parsed; - } - } - } + for (const line of lines) { + if (line.startsWith('data:')) { + dataLines.push(line.replace(/^data:\s*/, '')); + } else if (line.startsWith('event:')) { + eventName = line.replace(/^event:\s*/, ''); + } else if (line.startsWith('id:')) { + lastEventId = line.replace(/^id:\s*/, ''); + } else if (line.startsWith('retry:')) { + const parsed = Number.parseInt(line.replace(/^retry:\s*/, ''), 10); + if (!Number.isNaN(parsed)) { + retryDelay = parsed; + } + } + } - let data: unknown; - let parsedJson = false; + let data: unknown; + let parsedJson = false; - if (dataLines.length) { - const rawData = dataLines.join("\n"); - try { - data = JSON.parse(rawData); - parsedJson = true; - } catch { - data = rawData; - } - } + if (dataLines.length) { + const rawData = dataLines.join('\n'); + try { + data = JSON.parse(rawData); + parsedJson = true; + } catch { + data = rawData; + } + } - if (parsedJson) { - if (responseValidator) { - await responseValidator(data); - } + if (parsedJson) { + if (responseValidator) { + await responseValidator(data); + } - if (responseTransformer) { - data = await responseTransformer(data); - } - } + if (responseTransformer) { + data = await responseTransformer(data); + } + } - onSseEvent?.({ - data, - event: eventName, - id: lastEventId, - retry: retryDelay, - }); + onSseEvent?.({ + data, + event: eventName, + id: lastEventId, + retry: retryDelay, + }); - if (dataLines.length) { - yield data as any; - } - } - } - } finally { - signal.removeEventListener("abort", abortHandler); - reader.releaseLock(); - } + if (dataLines.length) { + yield data as any; + } + } + } + } finally { + signal.removeEventListener('abort', abortHandler); + reader.releaseLock(); + } - break; // exit loop on normal completion - } catch (error) { - // connection failed or aborted; retry after delay - onSseError?.(error); + break; // exit loop on normal completion + } catch (error) { + // connection failed or aborted; retry after delay + onSseError?.(error); - if (sseMaxRetryAttempts !== undefined && attempt >= sseMaxRetryAttempts) { - break; // stop after firing error - } + if (sseMaxRetryAttempts !== undefined && attempt >= sseMaxRetryAttempts) { + break; // stop after firing error + } - // exponential backoff: double retry each attempt, cap at 30s - const backoff = Math.min(retryDelay * 2 ** (attempt - 1), sseMaxRetryDelay ?? 30000); - await sleep(backoff); - } - } - }; + // exponential backoff: double retry each attempt, cap at 30s + const backoff = Math.min(retryDelay * 2 ** (attempt - 1), sseMaxRetryDelay ?? 30000); + await sleep(backoff); + } + } + }; - const stream = createStream(); + const stream = createStream(); - return { stream }; + return { stream }; }; diff --git a/app/client/api-client/core/types.gen.ts b/app/client/api-client/core/types.gen.ts index 62252e53..97463257 100644 --- a/app/client/api-client/core/types.gen.ts +++ b/app/client/api-client/core/types.gen.ts @@ -1,86 +1,104 @@ // This file is auto-generated by @hey-api/openapi-ts -import type { Auth, AuthToken } from "./auth.gen"; -import type { BodySerializer, QuerySerializer, QuerySerializerOptions } from "./bodySerializer.gen"; +import type { Auth, AuthToken } from './auth.gen'; +import type { BodySerializer, QuerySerializer, QuerySerializerOptions } from './bodySerializer.gen'; -export type HttpMethod = "connect" | "delete" | "get" | "head" | "options" | "patch" | "post" | "put" | "trace"; +export type HttpMethod = + | 'connect' + | 'delete' + | 'get' + | 'head' + | 'options' + | 'patch' + | 'post' + | 'put' + | 'trace'; -export type Client = { - /** - * Returns the final request URL. - */ - buildUrl: BuildUrlFn; - getConfig: () => Config; - request: RequestFn; - setConfig: (config: Config) => Config; +export type Client< + RequestFn = never, + Config = unknown, + MethodFn = never, + BuildUrlFn = never, + SseFn = never, +> = { + /** + * Returns the final request URL. + */ + buildUrl: BuildUrlFn; + getConfig: () => Config; + request: RequestFn; + setConfig: (config: Config) => Config; } & { - [K in HttpMethod]: MethodFn; + [K in HttpMethod]: MethodFn; } & ([SseFn] extends [never] ? { sse?: never } : { sse: { [K in HttpMethod]: SseFn } }); export interface Config { - /** - * Auth token or a function returning auth token. The resolved value will be - * added to the request payload as defined by its `security` array. - */ - auth?: ((auth: Auth) => Promise | AuthToken) | AuthToken; - /** - * A function for serializing request body parameter. By default, - * {@link JSON.stringify()} will be used. - */ - bodySerializer?: BodySerializer | null; - /** - * An object containing any HTTP headers that you want to pre-populate your - * `Headers` object with. - * - * {@link https://developer.mozilla.org/docs/Web/API/Headers/Headers#init See more} - */ - headers?: - | RequestInit["headers"] - | Record; - /** - * The request method. - * - * {@link https://developer.mozilla.org/docs/Web/API/fetch#method See more} - */ - method?: Uppercase; - /** - * A function for serializing request query parameters. By default, arrays - * will be exploded in form style, objects will be exploded in deepObject - * style, and reserved characters are percent-encoded. - * - * This method will have no effect if the native `paramsSerializer()` Axios - * API function is used. - * - * {@link https://swagger.io/docs/specification/serialization/#query View examples} - */ - querySerializer?: QuerySerializer | QuerySerializerOptions; - /** - * A function validating request data. This is useful if you want to ensure - * the request conforms to the desired shape, so it can be safely sent to - * the server. - */ - requestValidator?: (data: unknown) => Promise; - /** - * A function transforming response data before it's returned. This is useful - * for post-processing data, e.g. converting ISO strings into Date objects. - */ - responseTransformer?: (data: unknown) => Promise; - /** - * A function validating response data. This is useful if you want to ensure - * the response conforms to the desired shape, so it can be safely passed to - * the transformers and returned to the user. - */ - responseValidator?: (data: unknown) => Promise; + /** + * Auth token or a function returning auth token. The resolved value will be + * added to the request payload as defined by its `security` array. + */ + auth?: ((auth: Auth) => Promise | AuthToken) | AuthToken; + /** + * A function for serializing request body parameter. By default, + * {@link JSON.stringify()} will be used. + */ + bodySerializer?: BodySerializer | null; + /** + * An object containing any HTTP headers that you want to pre-populate your + * `Headers` object with. + * + * {@link https://developer.mozilla.org/docs/Web/API/Headers/Headers#init See more} + */ + headers?: + | RequestInit['headers'] + | Record< + string, + string | number | boolean | (string | number | boolean)[] | null | undefined | unknown + >; + /** + * The request method. + * + * {@link https://developer.mozilla.org/docs/Web/API/fetch#method See more} + */ + method?: Uppercase; + /** + * A function for serializing request query parameters. By default, arrays + * will be exploded in form style, objects will be exploded in deepObject + * style, and reserved characters are percent-encoded. + * + * This method will have no effect if the native `paramsSerializer()` Axios + * API function is used. + * + * {@link https://swagger.io/docs/specification/serialization/#query View examples} + */ + querySerializer?: QuerySerializer | QuerySerializerOptions; + /** + * A function validating request data. This is useful if you want to ensure + * the request conforms to the desired shape, so it can be safely sent to + * the server. + */ + requestValidator?: (data: unknown) => Promise; + /** + * A function transforming response data before it's returned. This is useful + * for post-processing data, e.g. converting ISO strings into Date objects. + */ + responseTransformer?: (data: unknown) => Promise; + /** + * A function validating response data. This is useful if you want to ensure + * the response conforms to the desired shape, so it can be safely passed to + * the transformers and returned to the user. + */ + responseValidator?: (data: unknown) => Promise; } type IsExactlyNeverOrNeverUndefined = [T] extends [never] - ? true - : [T] extends [never | undefined] - ? [undefined] extends [T] - ? false - : true - : false; + ? true + : [T] extends [never | undefined] + ? [undefined] extends [T] + ? false + : true + : false; export type OmitNever> = { - [K in keyof T as IsExactlyNeverOrNeverUndefined extends true ? never : K]: T[K]; + [K in keyof T as IsExactlyNeverOrNeverUndefined extends true ? never : K]: T[K]; }; diff --git a/app/client/api-client/core/utils.gen.ts b/app/client/api-client/core/utils.gen.ts index 7e48839f..e7ddbe35 100644 --- a/app/client/api-client/core/utils.gen.ts +++ b/app/client/api-client/core/utils.gen.ts @@ -1,137 +1,140 @@ // This file is auto-generated by @hey-api/openapi-ts -import type { BodySerializer, QuerySerializer } from "./bodySerializer.gen"; +import type { BodySerializer, QuerySerializer } from './bodySerializer.gen'; import { - type ArraySeparatorStyle, - serializeArrayParam, - serializeObjectParam, - serializePrimitiveParam, -} from "./pathSerializer.gen"; + type ArraySeparatorStyle, + serializeArrayParam, + serializeObjectParam, + serializePrimitiveParam, +} from './pathSerializer.gen'; export interface PathSerializer { - path: Record; - url: string; + path: Record; + url: string; } export const PATH_PARAM_RE = /\{[^{}]+\}/g; export const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => { - let url = _url; - const matches = _url.match(PATH_PARAM_RE); - if (matches) { - for (const match of matches) { - let explode = false; - let name = match.substring(1, match.length - 1); - let style: ArraySeparatorStyle = "simple"; + let url = _url; + const matches = _url.match(PATH_PARAM_RE); + if (matches) { + for (const match of matches) { + let explode = false; + let name = match.substring(1, match.length - 1); + let style: ArraySeparatorStyle = 'simple'; - if (name.endsWith("*")) { - explode = true; - name = name.substring(0, name.length - 1); - } + if (name.endsWith('*')) { + explode = true; + name = name.substring(0, name.length - 1); + } - if (name.startsWith(".")) { - name = name.substring(1); - style = "label"; - } else if (name.startsWith(";")) { - name = name.substring(1); - style = "matrix"; - } + if (name.startsWith('.')) { + name = name.substring(1); + style = 'label'; + } else if (name.startsWith(';')) { + name = name.substring(1); + style = 'matrix'; + } - const value = path[name]; + const value = path[name]; - if (value === undefined || value === null) { - continue; - } + if (value === undefined || value === null) { + continue; + } - if (Array.isArray(value)) { - url = url.replace(match, serializeArrayParam({ explode, name, style, value })); - continue; - } + if (Array.isArray(value)) { + url = url.replace(match, serializeArrayParam({ explode, name, style, value })); + continue; + } - if (typeof value === "object") { - url = url.replace( - match, - serializeObjectParam({ - explode, - name, - style, - value: value as Record, - valueOnly: true, - }), - ); - continue; - } + if (typeof value === 'object') { + url = url.replace( + match, + serializeObjectParam({ + explode, + name, + style, + value: value as Record, + valueOnly: true, + }), + ); + continue; + } - if (style === "matrix") { - url = url.replace( - match, - `;${serializePrimitiveParam({ - name, - value: value as string, - })}`, - ); - continue; - } + if (style === 'matrix') { + url = url.replace( + match, + `;${serializePrimitiveParam({ + name, + value: value as string, + })}`, + ); + continue; + } - const replaceValue = encodeURIComponent(style === "label" ? `.${value as string}` : (value as string)); - url = url.replace(match, replaceValue); - } - } - return url; + const replaceValue = encodeURIComponent( + style === 'label' ? `.${value as string}` : (value as string), + ); + url = url.replace(match, replaceValue); + } + } + return url; }; export const getUrl = ({ - baseUrl, - path, - query, - querySerializer, - url: _url, + baseUrl, + path, + query, + querySerializer, + url: _url, }: { - baseUrl?: string; - path?: Record; - query?: Record; - querySerializer: QuerySerializer; - url: string; + baseUrl?: string; + path?: Record; + query?: Record; + querySerializer: QuerySerializer; + url: string; }) => { - const pathUrl = _url.startsWith("/") ? _url : `/${_url}`; - let url = (baseUrl ?? "") + pathUrl; - if (path) { - url = defaultPathSerializer({ path, url }); - } - let search = query ? querySerializer(query) : ""; - if (search.startsWith("?")) { - search = search.substring(1); - } - if (search) { - url += `?${search}`; - } - return url; + const pathUrl = _url.startsWith('/') ? _url : `/${_url}`; + let url = (baseUrl ?? '') + pathUrl; + if (path) { + url = defaultPathSerializer({ path, url }); + } + let search = query ? querySerializer(query) : ''; + if (search.startsWith('?')) { + search = search.substring(1); + } + if (search) { + url += `?${search}`; + } + return url; }; export function getValidRequestBody(options: { - body?: unknown; - bodySerializer?: BodySerializer | null; - serializedBody?: unknown; + body?: unknown; + bodySerializer?: BodySerializer | null; + serializedBody?: unknown; }) { - const hasBody = options.body !== undefined; - const isSerializedBody = hasBody && options.bodySerializer; + const hasBody = options.body !== undefined; + const isSerializedBody = hasBody && options.bodySerializer; - if (isSerializedBody) { - if ("serializedBody" in options) { - const hasSerializedBody = options.serializedBody !== undefined && options.serializedBody !== ""; + if (isSerializedBody) { + if ('serializedBody' in options) { + const hasSerializedBody = + options.serializedBody !== undefined && options.serializedBody !== ''; - return hasSerializedBody ? options.serializedBody : null; - } + return hasSerializedBody ? options.serializedBody : null; + } - // not all clients implement a serializedBody property (i.e. client-axios) - return options.body !== "" ? options.body : null; - } + // not all clients implement a serializedBody property (i.e. client-axios) + return options.body !== '' ? options.body : null; + } - // plain/text body - if (hasBody) { - return options.body; - } + // plain/text body + if (hasBody) { + return options.body; + } - // no body was provided - return undefined; + // no body was provided + return undefined; } diff --git a/app/client/api-client/index.ts b/app/client/api-client/index.ts index dadecaf4..b93d38d8 100644 --- a/app/client/api-client/index.ts +++ b/app/client/api-client/index.ts @@ -13,21 +13,26 @@ export { deleteRepository, deleteSnapshot, deleteSnapshots, + deleteSsoInvitation, + deleteSsoProvider, deleteVolume, devPanelExec, downloadResticPassword, dumpSnapshot, + getAdminUsers, getBackupSchedule, getBackupScheduleForVolume, getDevPanel, getMirrorCompatibility, getNotificationDestination, + getPublicSsoProviders, getRegistrationStatus, getRepository, getRepositoryStats, getScheduleMirrors, getScheduleNotifications, getSnapshotDetails, + getSsoSettings, getStatus, getSystemInfo, getUpdates, @@ -101,6 +106,12 @@ export type { DeleteSnapshotsData, DeleteSnapshotsResponse, DeleteSnapshotsResponses, + DeleteSsoInvitationData, + DeleteSsoInvitationErrors, + DeleteSsoInvitationResponses, + DeleteSsoProviderData, + DeleteSsoProviderErrors, + DeleteSsoProviderResponses, DeleteVolumeData, DeleteVolumeResponse, DeleteVolumeResponses, @@ -114,6 +125,9 @@ export type { DumpSnapshotData, DumpSnapshotResponse, DumpSnapshotResponses, + GetAdminUsersData, + GetAdminUsersResponse, + GetAdminUsersResponses, GetBackupScheduleData, GetBackupScheduleForVolumeData, GetBackupScheduleForVolumeResponse, @@ -130,6 +144,9 @@ export type { GetNotificationDestinationErrors, GetNotificationDestinationResponse, GetNotificationDestinationResponses, + GetPublicSsoProvidersData, + GetPublicSsoProvidersResponse, + GetPublicSsoProvidersResponses, GetRegistrationStatusData, GetRegistrationStatusResponse, GetRegistrationStatusResponses, @@ -148,6 +165,9 @@ export type { GetSnapshotDetailsData, GetSnapshotDetailsResponse, GetSnapshotDetailsResponses, + GetSsoSettingsData, + GetSsoSettingsResponse, + GetSsoSettingsResponses, GetStatusData, GetStatusResponse, GetStatusResponses, diff --git a/app/client/api-client/sdk.gen.ts b/app/client/api-client/sdk.gen.ts index 14aa4fc2..4132f10f 100644 --- a/app/client/api-client/sdk.gen.ts +++ b/app/client/api-client/sdk.gen.ts @@ -1,855 +1,471 @@ // @ts-nocheck // This file is auto-generated by @hey-api/openapi-ts -import type { Client, Options as Options2, TDataShape } from "./client"; -import { client } from "./client.gen"; -import type { - BrowseFilesystemData, - BrowseFilesystemResponses, - CancelDoctorData, - CancelDoctorErrors, - CancelDoctorResponses, - CreateBackupScheduleData, - CreateBackupScheduleResponses, - CreateNotificationDestinationData, - CreateNotificationDestinationResponses, - CreateRepositoryData, - CreateRepositoryResponses, - CreateVolumeData, - CreateVolumeResponses, - DeleteBackupScheduleData, - DeleteBackupScheduleResponses, - DeleteNotificationDestinationData, - DeleteNotificationDestinationErrors, - DeleteNotificationDestinationResponses, - DeleteRepositoryData, - DeleteRepositoryResponses, - DeleteSnapshotData, - DeleteSnapshotResponses, - DeleteSnapshotsData, - DeleteSnapshotsResponses, - DeleteVolumeData, - DeleteVolumeResponses, - DevPanelExecData, - DevPanelExecErrors, - DevPanelExecResponses, - DownloadResticPasswordData, - DownloadResticPasswordResponses, - DumpSnapshotData, - DumpSnapshotResponses, - GetBackupScheduleData, - GetBackupScheduleForVolumeData, - GetBackupScheduleForVolumeResponses, - GetBackupScheduleResponses, - GetDevPanelData, - GetDevPanelResponses, - GetMirrorCompatibilityData, - GetMirrorCompatibilityResponses, - GetNotificationDestinationData, - GetNotificationDestinationErrors, - GetNotificationDestinationResponses, - GetRegistrationStatusData, - GetRegistrationStatusResponses, - GetRepositoryData, - GetRepositoryResponses, - GetRepositoryStatsData, - GetRepositoryStatsResponses, - GetScheduleMirrorsData, - GetScheduleMirrorsResponses, - GetScheduleNotificationsData, - GetScheduleNotificationsResponses, - GetSnapshotDetailsData, - GetSnapshotDetailsResponses, - GetStatusData, - GetStatusResponses, - GetSystemInfoData, - GetSystemInfoResponses, - GetUpdatesData, - GetUpdatesResponses, - GetUserDeletionImpactData, - GetUserDeletionImpactResponses, - GetVolumeData, - GetVolumeErrors, - GetVolumeResponses, - HealthCheckVolumeData, - HealthCheckVolumeErrors, - HealthCheckVolumeResponses, - ListBackupSchedulesData, - ListBackupSchedulesResponses, - ListFilesData, - ListFilesResponses, - ListNotificationDestinationsData, - ListNotificationDestinationsResponses, - ListRcloneRemotesData, - ListRcloneRemotesResponses, - ListRepositoriesData, - ListRepositoriesResponses, - ListSnapshotFilesData, - ListSnapshotFilesResponses, - ListSnapshotsData, - ListSnapshotsResponses, - ListVolumesData, - ListVolumesResponses, - MountVolumeData, - MountVolumeResponses, - RefreshSnapshotsData, - RefreshSnapshotsResponses, - ReorderBackupSchedulesData, - ReorderBackupSchedulesResponses, - RestoreSnapshotData, - RestoreSnapshotResponses, - RunBackupNowData, - RunBackupNowResponses, - RunForgetData, - RunForgetResponses, - SetRegistrationStatusData, - SetRegistrationStatusResponses, - StartDoctorData, - StartDoctorErrors, - StartDoctorResponses, - StopBackupData, - StopBackupErrors, - StopBackupResponses, - TagSnapshotsData, - TagSnapshotsResponses, - TestConnectionData, - TestConnectionResponses, - TestNotificationDestinationData, - TestNotificationDestinationErrors, - TestNotificationDestinationResponses, - UnlockRepositoryData, - UnlockRepositoryResponses, - UnmountVolumeData, - UnmountVolumeResponses, - UpdateBackupScheduleData, - UpdateBackupScheduleResponses, - UpdateNotificationDestinationData, - UpdateNotificationDestinationErrors, - UpdateNotificationDestinationResponses, - UpdateRepositoryData, - UpdateRepositoryErrors, - UpdateRepositoryResponses, - UpdateScheduleMirrorsData, - UpdateScheduleMirrorsResponses, - UpdateScheduleNotificationsData, - UpdateScheduleNotificationsResponses, - UpdateVolumeData, - UpdateVolumeErrors, - UpdateVolumeResponses, -} from "./types.gen"; +import type { Client, Options as Options2, TDataShape } from './client'; +import { client } from './client.gen'; +import type { BrowseFilesystemData, BrowseFilesystemResponses, CancelDoctorData, CancelDoctorErrors, CancelDoctorResponses, CreateBackupScheduleData, CreateBackupScheduleResponses, CreateNotificationDestinationData, CreateNotificationDestinationResponses, CreateRepositoryData, CreateRepositoryResponses, CreateVolumeData, CreateVolumeResponses, DeleteBackupScheduleData, DeleteBackupScheduleResponses, DeleteNotificationDestinationData, DeleteNotificationDestinationErrors, DeleteNotificationDestinationResponses, DeleteRepositoryData, DeleteRepositoryResponses, DeleteSnapshotData, DeleteSnapshotResponses, DeleteSnapshotsData, DeleteSnapshotsResponses, DeleteSsoInvitationData, DeleteSsoInvitationErrors, DeleteSsoInvitationResponses, DeleteSsoProviderData, DeleteSsoProviderErrors, DeleteSsoProviderResponses, DeleteVolumeData, DeleteVolumeResponses, DevPanelExecData, DevPanelExecErrors, DevPanelExecResponses, DownloadResticPasswordData, DownloadResticPasswordResponses, DumpSnapshotData, DumpSnapshotResponses, GetAdminUsersData, GetAdminUsersResponses, GetBackupScheduleData, GetBackupScheduleForVolumeData, GetBackupScheduleForVolumeResponses, GetBackupScheduleResponses, GetDevPanelData, GetDevPanelResponses, GetMirrorCompatibilityData, GetMirrorCompatibilityResponses, GetNotificationDestinationData, GetNotificationDestinationErrors, GetNotificationDestinationResponses, GetPublicSsoProvidersData, GetPublicSsoProvidersResponses, GetRegistrationStatusData, GetRegistrationStatusResponses, GetRepositoryData, GetRepositoryResponses, GetRepositoryStatsData, GetRepositoryStatsResponses, GetScheduleMirrorsData, GetScheduleMirrorsResponses, GetScheduleNotificationsData, GetScheduleNotificationsResponses, GetSnapshotDetailsData, GetSnapshotDetailsResponses, GetSsoSettingsData, GetSsoSettingsResponses, GetStatusData, GetStatusResponses, GetSystemInfoData, GetSystemInfoResponses, GetUpdatesData, GetUpdatesResponses, GetUserDeletionImpactData, GetUserDeletionImpactResponses, GetVolumeData, GetVolumeErrors, GetVolumeResponses, HealthCheckVolumeData, HealthCheckVolumeErrors, HealthCheckVolumeResponses, ListBackupSchedulesData, ListBackupSchedulesResponses, ListFilesData, ListFilesResponses, ListNotificationDestinationsData, ListNotificationDestinationsResponses, ListRcloneRemotesData, ListRcloneRemotesResponses, ListRepositoriesData, ListRepositoriesResponses, ListSnapshotFilesData, ListSnapshotFilesResponses, ListSnapshotsData, ListSnapshotsResponses, ListVolumesData, ListVolumesResponses, MountVolumeData, MountVolumeResponses, RefreshSnapshotsData, RefreshSnapshotsResponses, ReorderBackupSchedulesData, ReorderBackupSchedulesResponses, RestoreSnapshotData, RestoreSnapshotResponses, RunBackupNowData, RunBackupNowResponses, RunForgetData, RunForgetResponses, SetRegistrationStatusData, SetRegistrationStatusResponses, StartDoctorData, StartDoctorErrors, StartDoctorResponses, StopBackupData, StopBackupErrors, StopBackupResponses, TagSnapshotsData, TagSnapshotsResponses, TestConnectionData, TestConnectionResponses, TestNotificationDestinationData, TestNotificationDestinationErrors, TestNotificationDestinationResponses, UnlockRepositoryData, UnlockRepositoryResponses, UnmountVolumeData, UnmountVolumeResponses, UpdateBackupScheduleData, UpdateBackupScheduleResponses, UpdateNotificationDestinationData, UpdateNotificationDestinationErrors, UpdateNotificationDestinationResponses, UpdateRepositoryData, UpdateRepositoryErrors, UpdateRepositoryResponses, UpdateScheduleMirrorsData, UpdateScheduleMirrorsResponses, UpdateScheduleNotificationsData, UpdateScheduleNotificationsResponses, UpdateVolumeData, UpdateVolumeErrors, UpdateVolumeResponses } from './types.gen'; -export type Options = Options2< - TData, - ThrowOnError -> & { - /** - * You can provide a client instance returned by `createClient()` instead of - * individual options. This might be also useful if you want to implement a - * custom client. - */ - client?: Client; - /** - * You can pass arbitrary values through the `meta` object. This can be - * used to access values that aren't defined as part of the SDK function. - */ - meta?: Record; +export type Options = Options2 & { + /** + * You can provide a client instance returned by `createClient()` instead of + * individual options. This might be also useful if you want to implement a + * custom client. + */ + client?: Client; + /** + * You can pass arbitrary values through the `meta` object. This can be + * used to access values that aren't defined as part of the SDK function. + */ + meta?: Record; }; /** * Get authentication system status */ -export const getStatus = (options?: Options) => - (options?.client ?? client).get({ - url: "/api/v1/auth/status", - ...options, - }); +export const getStatus = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/auth/status', ...options }); + +/** + * Get public SSO providers for the instance + */ +export const getPublicSsoProviders = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/auth/sso-providers', ...options }); + +/** + * Get SSO providers and invitations for the active organization + */ +export const getSsoSettings = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/auth/sso-settings', ...options }); + +/** + * Delete an SSO provider + */ +export const deleteSsoProvider = (options: Options) => (options.client ?? client).delete({ url: '/api/v1/auth/sso-providers/{providerId}', ...options }); + +/** + * Delete an SSO invitation + */ +export const deleteSsoInvitation = (options: Options) => (options.client ?? client).delete({ url: '/api/v1/auth/sso-invitations/{invitationId}', ...options }); + +/** + * List admin users for settings management + */ +export const getAdminUsers = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/auth/admin-users', ...options }); /** * Get impact of deleting a user */ -export const getUserDeletionImpact = ( - options: Options, -) => - (options.client ?? client).get({ - url: "/api/v1/auth/deletion-impact/{userId}", - ...options, - }); +export const getUserDeletionImpact = (options: Options) => (options.client ?? client).get({ url: '/api/v1/auth/deletion-impact/{userId}', ...options }); /** * List all volumes */ -export const listVolumes = (options?: Options) => - (options?.client ?? client).get({ url: "/api/v1/volumes", ...options }); +export const listVolumes = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/volumes', ...options }); /** * Create a new volume */ -export const createVolume = (options?: Options) => - (options?.client ?? client).post({ - url: "/api/v1/volumes", - ...options, - headers: { - "Content-Type": "application/json", - ...options?.headers, - }, - }); +export const createVolume = (options?: Options) => (options?.client ?? client).post({ + url: '/api/v1/volumes', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options?.headers + } +}); /** * Test connection to backend */ -export const testConnection = ( - options?: Options, -) => - (options?.client ?? client).post({ - url: "/api/v1/volumes/test-connection", - ...options, - headers: { - "Content-Type": "application/json", - ...options?.headers, - }, - }); +export const testConnection = (options?: Options) => (options?.client ?? client).post({ + url: '/api/v1/volumes/test-connection', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options?.headers + } +}); /** * Delete a volume */ -export const deleteVolume = (options: Options) => - (options.client ?? client).delete({ - url: "/api/v1/volumes/{shortId}", - ...options, - }); +export const deleteVolume = (options: Options) => (options.client ?? client).delete({ url: '/api/v1/volumes/{shortId}', ...options }); /** * Get a volume by name */ -export const getVolume = (options: Options) => - (options.client ?? client).get({ - url: "/api/v1/volumes/{shortId}", - ...options, - }); +export const getVolume = (options: Options) => (options.client ?? client).get({ url: '/api/v1/volumes/{shortId}', ...options }); /** * Update a volume's configuration */ -export const updateVolume = (options: Options) => - (options.client ?? client).put({ - url: "/api/v1/volumes/{shortId}", - ...options, - headers: { - "Content-Type": "application/json", - ...options.headers, - }, - }); +export const updateVolume = (options: Options) => (options.client ?? client).put({ + url: '/api/v1/volumes/{shortId}', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); /** * Mount a volume */ -export const mountVolume = (options: Options) => - (options.client ?? client).post({ - url: "/api/v1/volumes/{shortId}/mount", - ...options, - }); +export const mountVolume = (options: Options) => (options.client ?? client).post({ url: '/api/v1/volumes/{shortId}/mount', ...options }); /** * Unmount a volume */ -export const unmountVolume = ( - options: Options, -) => - (options.client ?? client).post({ - url: "/api/v1/volumes/{shortId}/unmount", - ...options, - }); +export const unmountVolume = (options: Options) => (options.client ?? client).post({ url: '/api/v1/volumes/{shortId}/unmount', ...options }); /** * Perform a health check on a volume */ -export const healthCheckVolume = ( - options: Options, -) => - (options.client ?? client).post({ - url: "/api/v1/volumes/{shortId}/health-check", - ...options, - }); +export const healthCheckVolume = (options: Options) => (options.client ?? client).post({ url: '/api/v1/volumes/{shortId}/health-check', ...options }); /** * List files in a volume directory */ -export const listFiles = (options: Options) => - (options.client ?? client).get({ - url: "/api/v1/volumes/{shortId}/files", - ...options, - }); +export const listFiles = (options: Options) => (options.client ?? client).get({ url: '/api/v1/volumes/{shortId}/files', ...options }); /** * Browse directories on the host filesystem */ -export const browseFilesystem = ( - options?: Options, -) => - (options?.client ?? client).get({ - url: "/api/v1/volumes/filesystem/browse", - ...options, - }); +export const browseFilesystem = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/volumes/filesystem/browse', ...options }); /** * List all repositories */ -export const listRepositories = ( - options?: Options, -) => - (options?.client ?? client).get({ - url: "/api/v1/repositories", - ...options, - }); +export const listRepositories = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/repositories', ...options }); /** * Create a new restic repository */ -export const createRepository = ( - options?: Options, -) => - (options?.client ?? client).post({ - url: "/api/v1/repositories", - ...options, - headers: { - "Content-Type": "application/json", - ...options?.headers, - }, - }); +export const createRepository = (options?: Options) => (options?.client ?? client).post({ + url: '/api/v1/repositories', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options?.headers + } +}); /** * List all configured rclone remotes on the host system */ -export const listRcloneRemotes = ( - options?: Options, -) => - (options?.client ?? client).get({ - url: "/api/v1/repositories/rclone-remotes", - ...options, - }); +export const listRcloneRemotes = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/repositories/rclone-remotes', ...options }); /** * Delete a repository */ -export const deleteRepository = ( - options: Options, -) => - (options.client ?? client).delete({ - url: "/api/v1/repositories/{shortId}", - ...options, - }); +export const deleteRepository = (options: Options) => (options.client ?? client).delete({ url: '/api/v1/repositories/{shortId}', ...options }); /** * Get a single repository by ID */ -export const getRepository = ( - options: Options, -) => - (options.client ?? client).get({ - url: "/api/v1/repositories/{shortId}", - ...options, - }); +export const getRepository = (options: Options) => (options.client ?? client).get({ url: '/api/v1/repositories/{shortId}', ...options }); /** * Update a repository's name or settings */ -export const updateRepository = ( - options: Options, -) => - (options.client ?? client).patch({ - url: "/api/v1/repositories/{shortId}", - ...options, - headers: { - "Content-Type": "application/json", - ...options.headers, - }, - }); +export const updateRepository = (options: Options) => (options.client ?? client).patch({ + url: '/api/v1/repositories/{shortId}', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); /** * Get repository storage and compression statistics */ -export const getRepositoryStats = ( - options: Options, -) => - (options.client ?? client).get({ - url: "/api/v1/repositories/{shortId}/stats", - ...options, - }); +export const getRepositoryStats = (options: Options) => (options.client ?? client).get({ url: '/api/v1/repositories/{shortId}/stats', ...options }); /** * Delete multiple snapshots from a repository */ -export const deleteSnapshots = ( - options: Options, -) => - (options.client ?? client).delete({ - url: "/api/v1/repositories/{shortId}/snapshots", - ...options, - headers: { - "Content-Type": "application/json", - ...options.headers, - }, - }); +export const deleteSnapshots = (options: Options) => (options.client ?? client).delete({ + url: '/api/v1/repositories/{shortId}/snapshots', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); /** * List all snapshots in a repository */ -export const listSnapshots = ( - options: Options, -) => - (options.client ?? client).get({ - url: "/api/v1/repositories/{shortId}/snapshots", - ...options, - }); +export const listSnapshots = (options: Options) => (options.client ?? client).get({ url: '/api/v1/repositories/{shortId}/snapshots', ...options }); /** * Clear snapshot cache and force refresh from repository */ -export const refreshSnapshots = ( - options: Options, -) => - (options.client ?? client).post({ - url: "/api/v1/repositories/{shortId}/snapshots/refresh", - ...options, - }); +export const refreshSnapshots = (options: Options) => (options.client ?? client).post({ url: '/api/v1/repositories/{shortId}/snapshots/refresh', ...options }); /** * Delete a specific snapshot from a repository */ -export const deleteSnapshot = ( - options: Options, -) => - (options.client ?? client).delete({ - url: "/api/v1/repositories/{shortId}/snapshots/{snapshotId}", - ...options, - }); +export const deleteSnapshot = (options: Options) => (options.client ?? client).delete({ url: '/api/v1/repositories/{shortId}/snapshots/{snapshotId}', ...options }); /** * Get details of a specific snapshot */ -export const getSnapshotDetails = ( - options: Options, -) => - (options.client ?? client).get({ - url: "/api/v1/repositories/{shortId}/snapshots/{snapshotId}", - ...options, - }); +export const getSnapshotDetails = (options: Options) => (options.client ?? client).get({ url: '/api/v1/repositories/{shortId}/snapshots/{snapshotId}', ...options }); /** * List files and directories in a snapshot */ -export const listSnapshotFiles = ( - options: Options, -) => - (options.client ?? client).get({ - url: "/api/v1/repositories/{shortId}/snapshots/{snapshotId}/files", - ...options, - }); +export const listSnapshotFiles = (options: Options) => (options.client ?? client).get({ url: '/api/v1/repositories/{shortId}/snapshots/{snapshotId}/files', ...options }); /** * Download a snapshot path as a tar archive (folders) or raw file stream (single files) */ -export const dumpSnapshot = (options: Options) => - (options.client ?? client).get({ - url: "/api/v1/repositories/{shortId}/snapshots/{snapshotId}/dump", - ...options, - }); +export const dumpSnapshot = (options: Options) => (options.client ?? client).get({ url: '/api/v1/repositories/{shortId}/snapshots/{snapshotId}/dump', ...options }); /** * Restore a snapshot to a target path on the filesystem */ -export const restoreSnapshot = ( - options: Options, -) => - (options.client ?? client).post({ - url: "/api/v1/repositories/{shortId}/restore", - ...options, - headers: { - "Content-Type": "application/json", - ...options.headers, - }, - }); +export const restoreSnapshot = (options: Options) => (options.client ?? client).post({ + url: '/api/v1/repositories/{shortId}/restore', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); /** * Cancel a running doctor operation on a repository */ -export const cancelDoctor = (options: Options) => - (options.client ?? client).delete({ - url: "/api/v1/repositories/{shortId}/doctor", - ...options, - }); +export const cancelDoctor = (options: Options) => (options.client ?? client).delete({ url: '/api/v1/repositories/{shortId}/doctor', ...options }); /** * Start an asynchronous doctor operation on a repository to fix common issues (unlock, check, repair index). The operation runs in the background and sends results via SSE events. */ -export const startDoctor = (options: Options) => - (options.client ?? client).post({ - url: "/api/v1/repositories/{shortId}/doctor", - ...options, - }); +export const startDoctor = (options: Options) => (options.client ?? client).post({ url: '/api/v1/repositories/{shortId}/doctor', ...options }); /** * Unlock a repository by removing all stale locks */ -export const unlockRepository = ( - options: Options, -) => - (options.client ?? client).post({ - url: "/api/v1/repositories/{shortId}/unlock", - ...options, - }); +export const unlockRepository = (options: Options) => (options.client ?? client).post({ url: '/api/v1/repositories/{shortId}/unlock', ...options }); /** * Tag multiple snapshots in a repository */ -export const tagSnapshots = (options: Options) => - (options.client ?? client).post({ - url: "/api/v1/repositories/{shortId}/snapshots/tag", - ...options, - headers: { - "Content-Type": "application/json", - ...options.headers, - }, - }); +export const tagSnapshots = (options: Options) => (options.client ?? client).post({ + url: '/api/v1/repositories/{shortId}/snapshots/tag', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); /** * Execute a restic command against a repository (dev panel only) */ -export const devPanelExec = (options: Options) => - (options.client ?? client).sse.post({ - url: "/api/v1/repositories/{shortId}/exec", - ...options, - headers: { - "Content-Type": "application/json", - ...options.headers, - }, - }); +export const devPanelExec = (options: Options) => (options.client ?? client).sse.post({ + url: '/api/v1/repositories/{shortId}/exec', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); /** * List all backup schedules */ -export const listBackupSchedules = ( - options?: Options, -) => - (options?.client ?? client).get({ - url: "/api/v1/backups", - ...options, - }); +export const listBackupSchedules = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/backups', ...options }); /** * Create a new backup schedule for a volume */ -export const createBackupSchedule = ( - options?: Options, -) => - (options?.client ?? client).post({ - url: "/api/v1/backups", - ...options, - headers: { - "Content-Type": "application/json", - ...options?.headers, - }, - }); +export const createBackupSchedule = (options?: Options) => (options?.client ?? client).post({ + url: '/api/v1/backups', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options?.headers + } +}); /** * Delete a backup schedule */ -export const deleteBackupSchedule = ( - options: Options, -) => - (options.client ?? client).delete({ - url: "/api/v1/backups/{shortId}", - ...options, - }); +export const deleteBackupSchedule = (options: Options) => (options.client ?? client).delete({ url: '/api/v1/backups/{shortId}', ...options }); /** * Get a backup schedule by ID */ -export const getBackupSchedule = ( - options: Options, -) => - (options.client ?? client).get({ - url: "/api/v1/backups/{shortId}", - ...options, - }); +export const getBackupSchedule = (options: Options) => (options.client ?? client).get({ url: '/api/v1/backups/{shortId}', ...options }); /** * Update a backup schedule */ -export const updateBackupSchedule = ( - options: Options, -) => - (options.client ?? client).patch({ - url: "/api/v1/backups/{shortId}", - ...options, - headers: { - "Content-Type": "application/json", - ...options.headers, - }, - }); +export const updateBackupSchedule = (options: Options) => (options.client ?? client).patch({ + url: '/api/v1/backups/{shortId}', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); /** * Get a backup schedule for a specific volume */ -export const getBackupScheduleForVolume = ( - options: Options, -) => - (options.client ?? client).get({ - url: "/api/v1/backups/volume/{volumeShortId}", - ...options, - }); +export const getBackupScheduleForVolume = (options: Options) => (options.client ?? client).get({ url: '/api/v1/backups/volume/{volumeShortId}', ...options }); /** * Trigger a backup immediately for a schedule */ -export const runBackupNow = (options: Options) => - (options.client ?? client).post({ - url: "/api/v1/backups/{shortId}/run", - ...options, - }); +export const runBackupNow = (options: Options) => (options.client ?? client).post({ url: '/api/v1/backups/{shortId}/run', ...options }); /** * Stop a backup that is currently in progress */ -export const stopBackup = (options: Options) => - (options.client ?? client).post({ - url: "/api/v1/backups/{shortId}/stop", - ...options, - }); +export const stopBackup = (options: Options) => (options.client ?? client).post({ url: '/api/v1/backups/{shortId}/stop', ...options }); /** * Manually apply retention policy to clean up old snapshots */ -export const runForget = (options: Options) => - (options.client ?? client).post({ - url: "/api/v1/backups/{shortId}/forget", - ...options, - }); +export const runForget = (options: Options) => (options.client ?? client).post({ url: '/api/v1/backups/{shortId}/forget', ...options }); /** * Get notification assignments for a backup schedule */ -export const getScheduleNotifications = ( - options: Options, -) => - (options.client ?? client).get({ - url: "/api/v1/backups/{shortId}/notifications", - ...options, - }); +export const getScheduleNotifications = (options: Options) => (options.client ?? client).get({ url: '/api/v1/backups/{shortId}/notifications', ...options }); /** * Update notification assignments for a backup schedule */ -export const updateScheduleNotifications = ( - options: Options, -) => - (options.client ?? client).put({ - url: "/api/v1/backups/{shortId}/notifications", - ...options, - headers: { - "Content-Type": "application/json", - ...options.headers, - }, - }); +export const updateScheduleNotifications = (options: Options) => (options.client ?? client).put({ + url: '/api/v1/backups/{shortId}/notifications', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); /** * Get mirror repository assignments for a backup schedule */ -export const getScheduleMirrors = ( - options: Options, -) => - (options.client ?? client).get({ - url: "/api/v1/backups/{shortId}/mirrors", - ...options, - }); +export const getScheduleMirrors = (options: Options) => (options.client ?? client).get({ url: '/api/v1/backups/{shortId}/mirrors', ...options }); /** * Update mirror repository assignments for a backup schedule */ -export const updateScheduleMirrors = ( - options: Options, -) => - (options.client ?? client).put({ - url: "/api/v1/backups/{shortId}/mirrors", - ...options, - headers: { - "Content-Type": "application/json", - ...options.headers, - }, - }); +export const updateScheduleMirrors = (options: Options) => (options.client ?? client).put({ + url: '/api/v1/backups/{shortId}/mirrors', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); /** * Get mirror compatibility info for all repositories relative to a backup schedule's primary repository */ -export const getMirrorCompatibility = ( - options: Options, -) => - (options.client ?? client).get({ - url: "/api/v1/backups/{shortId}/mirrors/compatibility", - ...options, - }); +export const getMirrorCompatibility = (options: Options) => (options.client ?? client).get({ url: '/api/v1/backups/{shortId}/mirrors/compatibility', ...options }); /** * Reorder backup schedules by providing an array of schedule short IDs in the desired order */ -export const reorderBackupSchedules = ( - options?: Options, -) => - (options?.client ?? client).post({ - url: "/api/v1/backups/reorder", - ...options, - headers: { - "Content-Type": "application/json", - ...options?.headers, - }, - }); +export const reorderBackupSchedules = (options?: Options) => (options?.client ?? client).post({ + url: '/api/v1/backups/reorder', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options?.headers + } +}); /** * List all notification destinations */ -export const listNotificationDestinations = ( - options?: Options, -) => - (options?.client ?? client).get({ - url: "/api/v1/notifications/destinations", - ...options, - }); +export const listNotificationDestinations = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/notifications/destinations', ...options }); /** * Create a new notification destination */ -export const createNotificationDestination = ( - options?: Options, -) => - (options?.client ?? client).post({ - url: "/api/v1/notifications/destinations", - ...options, - headers: { - "Content-Type": "application/json", - ...options?.headers, - }, - }); +export const createNotificationDestination = (options?: Options) => (options?.client ?? client).post({ + url: '/api/v1/notifications/destinations', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options?.headers + } +}); /** * Delete a notification destination */ -export const deleteNotificationDestination = ( - options: Options, -) => - (options.client ?? client).delete< - DeleteNotificationDestinationResponses, - DeleteNotificationDestinationErrors, - ThrowOnError - >({ url: "/api/v1/notifications/destinations/{id}", ...options }); +export const deleteNotificationDestination = (options: Options) => (options.client ?? client).delete({ url: '/api/v1/notifications/destinations/{id}', ...options }); /** * Get a notification destination by ID */ -export const getNotificationDestination = ( - options: Options, -) => - (options.client ?? client).get({ - url: "/api/v1/notifications/destinations/{id}", - ...options, - }); +export const getNotificationDestination = (options: Options) => (options.client ?? client).get({ url: '/api/v1/notifications/destinations/{id}', ...options }); /** * Update a notification destination */ -export const updateNotificationDestination = ( - options: Options, -) => - (options.client ?? client).patch< - UpdateNotificationDestinationResponses, - UpdateNotificationDestinationErrors, - ThrowOnError - >({ - url: "/api/v1/notifications/destinations/{id}", - ...options, - headers: { - "Content-Type": "application/json", - ...options.headers, - }, - }); +export const updateNotificationDestination = (options: Options) => (options.client ?? client).patch({ + url: '/api/v1/notifications/destinations/{id}', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); /** * Test a notification destination by sending a test message */ -export const testNotificationDestination = ( - options: Options, -) => - (options.client ?? client).post< - TestNotificationDestinationResponses, - TestNotificationDestinationErrors, - ThrowOnError - >({ url: "/api/v1/notifications/destinations/{id}/test", ...options }); +export const testNotificationDestination = (options: Options) => (options.client ?? client).post({ url: '/api/v1/notifications/destinations/{id}/test', ...options }); /** * Get system information including available capabilities */ -export const getSystemInfo = ( - options?: Options, -) => - (options?.client ?? client).get({ - url: "/api/v1/system/info", - ...options, - }); +export const getSystemInfo = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/system/info', ...options }); /** * Check for application updates from GitHub */ -export const getUpdates = (options?: Options) => - (options?.client ?? client).get({ - url: "/api/v1/system/updates", - ...options, - }); +export const getUpdates = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/system/updates', ...options }); /** * Get the current registration status for new users */ -export const getRegistrationStatus = ( - options?: Options, -) => - (options?.client ?? client).get({ - url: "/api/v1/system/registration-status", - ...options, - }); +export const getRegistrationStatus = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/system/registration-status', ...options }); /** * Update the registration status for new users. Requires global admin role. */ -export const setRegistrationStatus = ( - options?: Options, -) => - (options?.client ?? client).put({ - url: "/api/v1/system/registration-status", - ...options, - headers: { - "Content-Type": "application/json", - ...options?.headers, - }, - }); +export const setRegistrationStatus = (options?: Options) => (options?.client ?? client).put({ + url: '/api/v1/system/registration-status', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options?.headers + } +}); /** * Download the organization's Restic password for backup recovery. Requires organization owner or admin role and password re-authentication. */ -export const downloadResticPassword = ( - options?: Options, -) => - (options?.client ?? client).post({ - url: "/api/v1/system/restic-password", - ...options, - headers: { - "Content-Type": "application/json", - ...options?.headers, - }, - }); +export const downloadResticPassword = (options?: Options) => (options?.client ?? client).post({ + url: '/api/v1/system/restic-password', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options?.headers + } +}); /** * Get the dev panel status */ -export const getDevPanel = (options?: Options) => - (options?.client ?? client).get({ - url: "/api/v1/system/dev-panel", - ...options, - }); +export const getDevPanel = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/system/dev-panel', ...options }); diff --git a/app/client/api-client/types.gen.ts b/app/client/api-client/types.gen.ts index eac7e763..60076839 100644 --- a/app/client/api-client/types.gen.ts +++ b/app/client/api-client/types.gen.ts @@ -2,4696 +2,4599 @@ // This file is auto-generated by @hey-api/openapi-ts export type ClientOptions = { - baseUrl: "http://localhost:4096" | (string & {}); + baseUrl: 'http://localhost:4096' | (string & {}); }; export type GetStatusData = { - body?: never; - path?: never; - query?: never; - url: "/api/v1/auth/status"; + body?: never; + path?: never; + query?: never; + url: '/api/v1/auth/status'; }; export type GetStatusResponses = { - /** - * Authentication system status - */ - 200: { - hasUsers: boolean; - }; + /** + * Authentication system status + */ + 200: { + hasUsers: boolean; + }; }; export type GetStatusResponse = GetStatusResponses[keyof GetStatusResponses]; +export type GetPublicSsoProvidersData = { + body?: never; + path?: never; + query?: never; + url: '/api/v1/auth/sso-providers'; +}; + +export type GetPublicSsoProvidersResponses = { + /** + * List of public SSO providers + */ + 200: { + providers: Array<{ + organizationSlug: string; + providerId: string; + }>; + }; +}; + +export type GetPublicSsoProvidersResponse = GetPublicSsoProvidersResponses[keyof GetPublicSsoProvidersResponses]; + +export type GetSsoSettingsData = { + body?: never; + path?: never; + query?: never; + url: '/api/v1/auth/sso-settings'; +}; + +export type GetSsoSettingsResponses = { + /** + * SSO settings for the active organization + */ + 200: { + invitations: Array<{ + email: string; + expiresAt: string; + id: string; + role: string; + status: string; + }>; + providers: Array<{ + domain: string; + issuer: string; + organizationId: string | null; + providerId: string; + type: string; + }>; + }; +}; + +export type GetSsoSettingsResponse = GetSsoSettingsResponses[keyof GetSsoSettingsResponses]; + +export type DeleteSsoProviderData = { + body?: never; + path: { + providerId: string; + }; + query?: never; + url: '/api/v1/auth/sso-providers/{providerId}'; +}; + +export type DeleteSsoProviderErrors = { + /** + * Forbidden + */ + 403: unknown; +}; + +export type DeleteSsoProviderResponses = { + /** + * SSO provider deleted successfully + */ + 200: unknown; +}; + +export type DeleteSsoInvitationData = { + body?: never; + path: { + invitationId: string; + }; + query?: never; + url: '/api/v1/auth/sso-invitations/{invitationId}'; +}; + +export type DeleteSsoInvitationErrors = { + /** + * Forbidden + */ + 403: unknown; +}; + +export type DeleteSsoInvitationResponses = { + /** + * SSO invitation deleted successfully + */ + 200: unknown; +}; + +export type GetAdminUsersData = { + body?: never; + path?: never; + query?: never; + url: '/api/v1/auth/admin-users'; +}; + +export type GetAdminUsersResponses = { + /** + * List of users with roles and status + */ + 200: { + limit: number; + total: number; + users: Array<{ + banned: boolean; + email: string; + id: string; + name: string | null; + role: string; + }>; + }; +}; + +export type GetAdminUsersResponse = GetAdminUsersResponses[keyof GetAdminUsersResponses]; + export type GetUserDeletionImpactData = { - body?: never; - path: { - userId: string; - }; - query?: never; - url: "/api/v1/auth/deletion-impact/{userId}"; + body?: never; + path: { + userId: string; + }; + query?: never; + url: '/api/v1/auth/deletion-impact/{userId}'; }; export type GetUserDeletionImpactResponses = { - /** - * List of organizations and resources to be deleted - */ - 200: { - organizations: Array<{ - id: string; - name: string; - resources: { - backupSchedulesCount: number; - repositoriesCount: number; - volumesCount: number; - }; - }>; - }; + /** + * List of organizations and resources to be deleted + */ + 200: { + organizations: Array<{ + id: string; + name: string; + resources: { + backupSchedulesCount: number; + repositoriesCount: number; + volumesCount: number; + }; + }>; + }; }; export type GetUserDeletionImpactResponse = GetUserDeletionImpactResponses[keyof GetUserDeletionImpactResponses]; export type ListVolumesData = { - body?: never; - path?: never; - query?: never; - url: "/api/v1/volumes"; + body?: never; + path?: never; + query?: never; + url: '/api/v1/volumes'; }; export type ListVolumesResponses = { - /** - * A list of volumes - */ - 200: Array<{ - autoRemount: boolean; - config: - | { - backend: "directory"; - path: string; - readOnly?: false; - } - | { - backend: "nfs"; - exportPath: string; - server: string; - version: "3" | "4" | "4.1"; - port?: number; - readOnly?: boolean; - } - | { - backend: "rclone"; - path: string; - remote: string; - readOnly?: boolean; - } - | { - backend: "sftp"; - host: string; - path: string; - username: string; - port?: number; - skipHostKeyCheck?: boolean; - knownHosts?: string; - password?: string; - privateKey?: string; - readOnly?: boolean; - } - | { - backend: "smb"; - server: string; - share: string; - vers?: "1.0" | "2.0" | "2.1" | "3.0" | "auto"; - port?: number; - domain?: string; - guest?: boolean; - password?: string; - readOnly?: boolean; - username?: string; - } - | { - backend: "webdav"; - path: string; - server: string; - port?: number; - password?: string; - readOnly?: boolean; - ssl?: boolean; - username?: string; - }; - createdAt: number; - id: number; - lastError: string | null; - lastHealthCheck: number; - name: string; - shortId: string; - status: "error" | "mounted" | "unmounted"; - type: "directory" | "nfs" | "rclone" | "sftp" | "smb" | "webdav"; - updatedAt: number; - }>; + /** + * A list of volumes + */ + 200: Array<{ + autoRemount: boolean; + config: { + backend: 'directory'; + path: string; + readOnly?: false; + } | { + backend: 'nfs'; + exportPath: string; + server: string; + version: '3' | '4' | '4.1'; + port?: number; + readOnly?: boolean; + } | { + backend: 'rclone'; + path: string; + remote: string; + readOnly?: boolean; + } | { + backend: 'sftp'; + host: string; + path: string; + username: string; + port?: number; + skipHostKeyCheck?: boolean; + knownHosts?: string; + password?: string; + privateKey?: string; + readOnly?: boolean; + } | { + backend: 'smb'; + server: string; + share: string; + vers?: '1.0' | '2.0' | '2.1' | '3.0' | 'auto'; + port?: number; + domain?: string; + guest?: boolean; + password?: string; + readOnly?: boolean; + username?: string; + } | { + backend: 'webdav'; + path: string; + server: string; + port?: number; + password?: string; + readOnly?: boolean; + ssl?: boolean; + username?: string; + }; + createdAt: number; + id: number; + lastError: string | null; + lastHealthCheck: number; + name: string; + shortId: string; + status: 'error' | 'mounted' | 'unmounted'; + type: 'directory' | 'nfs' | 'rclone' | 'sftp' | 'smb' | 'webdav'; + updatedAt: number; + }>; }; export type ListVolumesResponse = ListVolumesResponses[keyof ListVolumesResponses]; export type CreateVolumeData = { - body?: { - config: - | { - backend: "directory"; - path: string; - readOnly?: false; - } - | { - backend: "nfs"; - exportPath: string; - server: string; - version: "3" | "4" | "4.1"; - port?: number; - readOnly?: boolean; - } - | { - backend: "rclone"; - path: string; - remote: string; - readOnly?: boolean; - } - | { - backend: "sftp"; - host: string; - path: string; - username: string; - port?: number; - skipHostKeyCheck?: boolean; - knownHosts?: string; - password?: string; - privateKey?: string; - readOnly?: boolean; - } - | { - backend: "smb"; - server: string; - share: string; - vers?: "1.0" | "2.0" | "2.1" | "3.0" | "auto"; - port?: number; - domain?: string; - guest?: boolean; - password?: string; - readOnly?: boolean; - username?: string; - } - | { - backend: "webdav"; - path: string; - server: string; - port?: number; - password?: string; - readOnly?: boolean; - ssl?: boolean; - username?: string; - }; - name: string; - }; - path?: never; - query?: never; - url: "/api/v1/volumes"; + body?: { + config: { + backend: 'directory'; + path: string; + readOnly?: false; + } | { + backend: 'nfs'; + exportPath: string; + server: string; + version: '3' | '4' | '4.1'; + port?: number; + readOnly?: boolean; + } | { + backend: 'rclone'; + path: string; + remote: string; + readOnly?: boolean; + } | { + backend: 'sftp'; + host: string; + path: string; + username: string; + port?: number; + skipHostKeyCheck?: boolean; + knownHosts?: string; + password?: string; + privateKey?: string; + readOnly?: boolean; + } | { + backend: 'smb'; + server: string; + share: string; + vers?: '1.0' | '2.0' | '2.1' | '3.0' | 'auto'; + port?: number; + domain?: string; + guest?: boolean; + password?: string; + readOnly?: boolean; + username?: string; + } | { + backend: 'webdav'; + path: string; + server: string; + port?: number; + password?: string; + readOnly?: boolean; + ssl?: boolean; + username?: string; + }; + name: string; + }; + path?: never; + query?: never; + url: '/api/v1/volumes'; }; export type CreateVolumeResponses = { - /** - * Volume created successfully - */ - 201: { - autoRemount: boolean; - config: - | { - backend: "directory"; - path: string; - readOnly?: false; - } - | { - backend: "nfs"; - exportPath: string; - server: string; - version: "3" | "4" | "4.1"; - port?: number; - readOnly?: boolean; - } - | { - backend: "rclone"; - path: string; - remote: string; - readOnly?: boolean; - } - | { - backend: "sftp"; - host: string; - path: string; - username: string; - port?: number; - skipHostKeyCheck?: boolean; - knownHosts?: string; - password?: string; - privateKey?: string; - readOnly?: boolean; - } - | { - backend: "smb"; - server: string; - share: string; - vers?: "1.0" | "2.0" | "2.1" | "3.0" | "auto"; - port?: number; - domain?: string; - guest?: boolean; - password?: string; - readOnly?: boolean; - username?: string; - } - | { - backend: "webdav"; - path: string; - server: string; - port?: number; - password?: string; - readOnly?: boolean; - ssl?: boolean; - username?: string; - }; - createdAt: number; - id: number; - lastError: string | null; - lastHealthCheck: number; - name: string; - shortId: string; - status: "error" | "mounted" | "unmounted"; - type: "directory" | "nfs" | "rclone" | "sftp" | "smb" | "webdav"; - updatedAt: number; - }; + /** + * Volume created successfully + */ + 201: { + autoRemount: boolean; + config: { + backend: 'directory'; + path: string; + readOnly?: false; + } | { + backend: 'nfs'; + exportPath: string; + server: string; + version: '3' | '4' | '4.1'; + port?: number; + readOnly?: boolean; + } | { + backend: 'rclone'; + path: string; + remote: string; + readOnly?: boolean; + } | { + backend: 'sftp'; + host: string; + path: string; + username: string; + port?: number; + skipHostKeyCheck?: boolean; + knownHosts?: string; + password?: string; + privateKey?: string; + readOnly?: boolean; + } | { + backend: 'smb'; + server: string; + share: string; + vers?: '1.0' | '2.0' | '2.1' | '3.0' | 'auto'; + port?: number; + domain?: string; + guest?: boolean; + password?: string; + readOnly?: boolean; + username?: string; + } | { + backend: 'webdav'; + path: string; + server: string; + port?: number; + password?: string; + readOnly?: boolean; + ssl?: boolean; + username?: string; + }; + createdAt: number; + id: number; + lastError: string | null; + lastHealthCheck: number; + name: string; + shortId: string; + status: 'error' | 'mounted' | 'unmounted'; + type: 'directory' | 'nfs' | 'rclone' | 'sftp' | 'smb' | 'webdav'; + updatedAt: number; + }; }; export type CreateVolumeResponse = CreateVolumeResponses[keyof CreateVolumeResponses]; export type TestConnectionData = { - body?: { - config: - | { - backend: "directory"; - path: string; - readOnly?: false; - } - | { - backend: "nfs"; - exportPath: string; - server: string; - version: "3" | "4" | "4.1"; - port?: number; - readOnly?: boolean; - } - | { - backend: "rclone"; - path: string; - remote: string; - readOnly?: boolean; - } - | { - backend: "sftp"; - host: string; - path: string; - username: string; - port?: number; - skipHostKeyCheck?: boolean; - knownHosts?: string; - password?: string; - privateKey?: string; - readOnly?: boolean; - } - | { - backend: "smb"; - server: string; - share: string; - vers?: "1.0" | "2.0" | "2.1" | "3.0" | "auto"; - port?: number; - domain?: string; - guest?: boolean; - password?: string; - readOnly?: boolean; - username?: string; - } - | { - backend: "webdav"; - path: string; - server: string; - port?: number; - password?: string; - readOnly?: boolean; - ssl?: boolean; - username?: string; - }; - }; - path?: never; - query?: never; - url: "/api/v1/volumes/test-connection"; + body?: { + config: { + backend: 'directory'; + path: string; + readOnly?: false; + } | { + backend: 'nfs'; + exportPath: string; + server: string; + version: '3' | '4' | '4.1'; + port?: number; + readOnly?: boolean; + } | { + backend: 'rclone'; + path: string; + remote: string; + readOnly?: boolean; + } | { + backend: 'sftp'; + host: string; + path: string; + username: string; + port?: number; + skipHostKeyCheck?: boolean; + knownHosts?: string; + password?: string; + privateKey?: string; + readOnly?: boolean; + } | { + backend: 'smb'; + server: string; + share: string; + vers?: '1.0' | '2.0' | '2.1' | '3.0' | 'auto'; + port?: number; + domain?: string; + guest?: boolean; + password?: string; + readOnly?: boolean; + username?: string; + } | { + backend: 'webdav'; + path: string; + server: string; + port?: number; + password?: string; + readOnly?: boolean; + ssl?: boolean; + username?: string; + }; + }; + path?: never; + query?: never; + url: '/api/v1/volumes/test-connection'; }; export type TestConnectionResponses = { - /** - * Connection test result - */ - 200: { - message: string; - success: boolean; - }; + /** + * Connection test result + */ + 200: { + message: string; + success: boolean; + }; }; export type TestConnectionResponse = TestConnectionResponses[keyof TestConnectionResponses]; export type DeleteVolumeData = { - body?: never; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/volumes/{shortId}"; + body?: never; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/volumes/{shortId}'; }; export type DeleteVolumeResponses = { - /** - * Volume deleted successfully - */ - 200: { - message: string; - }; + /** + * Volume deleted successfully + */ + 200: { + message: string; + }; }; export type DeleteVolumeResponse = DeleteVolumeResponses[keyof DeleteVolumeResponses]; export type GetVolumeData = { - body?: never; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/volumes/{shortId}"; + body?: never; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/volumes/{shortId}'; }; export type GetVolumeErrors = { - /** - * Volume not found - */ - 404: unknown; + /** + * Volume not found + */ + 404: unknown; }; export type GetVolumeResponses = { - /** - * Volume details - */ - 200: { - statfs: { - free: number; - total: number; - used: number; - }; - volume: { - autoRemount: boolean; - config: - | { - backend: "directory"; - path: string; - readOnly?: false; - } - | { - backend: "nfs"; - exportPath: string; - server: string; - version: "3" | "4" | "4.1"; - port?: number; - readOnly?: boolean; - } - | { - backend: "rclone"; - path: string; - remote: string; - readOnly?: boolean; - } - | { - backend: "sftp"; - host: string; - path: string; - username: string; - port?: number; - skipHostKeyCheck?: boolean; - knownHosts?: string; - password?: string; - privateKey?: string; - readOnly?: boolean; - } - | { - backend: "smb"; - server: string; - share: string; - vers?: "1.0" | "2.0" | "2.1" | "3.0" | "auto"; - port?: number; - domain?: string; - guest?: boolean; - password?: string; - readOnly?: boolean; - username?: string; - } - | { - backend: "webdav"; - path: string; - server: string; - port?: number; - password?: string; - readOnly?: boolean; - ssl?: boolean; - username?: string; - }; - createdAt: number; - id: number; - lastError: string | null; - lastHealthCheck: number; - name: string; - shortId: string; - status: "error" | "mounted" | "unmounted"; - type: "directory" | "nfs" | "rclone" | "sftp" | "smb" | "webdav"; - updatedAt: number; - }; - }; + /** + * Volume details + */ + 200: { + statfs: { + free: number; + total: number; + used: number; + }; + volume: { + autoRemount: boolean; + config: { + backend: 'directory'; + path: string; + readOnly?: false; + } | { + backend: 'nfs'; + exportPath: string; + server: string; + version: '3' | '4' | '4.1'; + port?: number; + readOnly?: boolean; + } | { + backend: 'rclone'; + path: string; + remote: string; + readOnly?: boolean; + } | { + backend: 'sftp'; + host: string; + path: string; + username: string; + port?: number; + skipHostKeyCheck?: boolean; + knownHosts?: string; + password?: string; + privateKey?: string; + readOnly?: boolean; + } | { + backend: 'smb'; + server: string; + share: string; + vers?: '1.0' | '2.0' | '2.1' | '3.0' | 'auto'; + port?: number; + domain?: string; + guest?: boolean; + password?: string; + readOnly?: boolean; + username?: string; + } | { + backend: 'webdav'; + path: string; + server: string; + port?: number; + password?: string; + readOnly?: boolean; + ssl?: boolean; + username?: string; + }; + createdAt: number; + id: number; + lastError: string | null; + lastHealthCheck: number; + name: string; + shortId: string; + status: 'error' | 'mounted' | 'unmounted'; + type: 'directory' | 'nfs' | 'rclone' | 'sftp' | 'smb' | 'webdav'; + updatedAt: number; + }; + }; }; export type GetVolumeResponse = GetVolumeResponses[keyof GetVolumeResponses]; export type UpdateVolumeData = { - body?: { - autoRemount?: boolean; - config?: - | { - backend: "directory"; - path: string; - readOnly?: false; - } - | { - backend: "nfs"; - exportPath: string; - server: string; - version: "3" | "4" | "4.1"; - port?: number; - readOnly?: boolean; - } - | { - backend: "rclone"; - path: string; - remote: string; - readOnly?: boolean; - } - | { - backend: "sftp"; - host: string; - path: string; - username: string; - port?: number; - skipHostKeyCheck?: boolean; - knownHosts?: string; - password?: string; - privateKey?: string; - readOnly?: boolean; - } - | { - backend: "smb"; - server: string; - share: string; - vers?: "1.0" | "2.0" | "2.1" | "3.0" | "auto"; - port?: number; - domain?: string; - guest?: boolean; - password?: string; - readOnly?: boolean; - username?: string; - } - | { - backend: "webdav"; - path: string; - server: string; - port?: number; - password?: string; - readOnly?: boolean; - ssl?: boolean; - username?: string; - }; - name?: string; - }; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/volumes/{shortId}"; + body?: { + autoRemount?: boolean; + config?: { + backend: 'directory'; + path: string; + readOnly?: false; + } | { + backend: 'nfs'; + exportPath: string; + server: string; + version: '3' | '4' | '4.1'; + port?: number; + readOnly?: boolean; + } | { + backend: 'rclone'; + path: string; + remote: string; + readOnly?: boolean; + } | { + backend: 'sftp'; + host: string; + path: string; + username: string; + port?: number; + skipHostKeyCheck?: boolean; + knownHosts?: string; + password?: string; + privateKey?: string; + readOnly?: boolean; + } | { + backend: 'smb'; + server: string; + share: string; + vers?: '1.0' | '2.0' | '2.1' | '3.0' | 'auto'; + port?: number; + domain?: string; + guest?: boolean; + password?: string; + readOnly?: boolean; + username?: string; + } | { + backend: 'webdav'; + path: string; + server: string; + port?: number; + password?: string; + readOnly?: boolean; + ssl?: boolean; + username?: string; + }; + name?: string; + }; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/volumes/{shortId}'; }; export type UpdateVolumeErrors = { - /** - * Volume not found - */ - 404: unknown; + /** + * Volume not found + */ + 404: unknown; }; export type UpdateVolumeResponses = { - /** - * Volume updated successfully - */ - 200: { - autoRemount: boolean; - config: - | { - backend: "directory"; - path: string; - readOnly?: false; - } - | { - backend: "nfs"; - exportPath: string; - server: string; - version: "3" | "4" | "4.1"; - port?: number; - readOnly?: boolean; - } - | { - backend: "rclone"; - path: string; - remote: string; - readOnly?: boolean; - } - | { - backend: "sftp"; - host: string; - path: string; - username: string; - port?: number; - skipHostKeyCheck?: boolean; - knownHosts?: string; - password?: string; - privateKey?: string; - readOnly?: boolean; - } - | { - backend: "smb"; - server: string; - share: string; - vers?: "1.0" | "2.0" | "2.1" | "3.0" | "auto"; - port?: number; - domain?: string; - guest?: boolean; - password?: string; - readOnly?: boolean; - username?: string; - } - | { - backend: "webdav"; - path: string; - server: string; - port?: number; - password?: string; - readOnly?: boolean; - ssl?: boolean; - username?: string; - }; - createdAt: number; - id: number; - lastError: string | null; - lastHealthCheck: number; - name: string; - shortId: string; - status: "error" | "mounted" | "unmounted"; - type: "directory" | "nfs" | "rclone" | "sftp" | "smb" | "webdav"; - updatedAt: number; - }; + /** + * Volume updated successfully + */ + 200: { + autoRemount: boolean; + config: { + backend: 'directory'; + path: string; + readOnly?: false; + } | { + backend: 'nfs'; + exportPath: string; + server: string; + version: '3' | '4' | '4.1'; + port?: number; + readOnly?: boolean; + } | { + backend: 'rclone'; + path: string; + remote: string; + readOnly?: boolean; + } | { + backend: 'sftp'; + host: string; + path: string; + username: string; + port?: number; + skipHostKeyCheck?: boolean; + knownHosts?: string; + password?: string; + privateKey?: string; + readOnly?: boolean; + } | { + backend: 'smb'; + server: string; + share: string; + vers?: '1.0' | '2.0' | '2.1' | '3.0' | 'auto'; + port?: number; + domain?: string; + guest?: boolean; + password?: string; + readOnly?: boolean; + username?: string; + } | { + backend: 'webdav'; + path: string; + server: string; + port?: number; + password?: string; + readOnly?: boolean; + ssl?: boolean; + username?: string; + }; + createdAt: number; + id: number; + lastError: string | null; + lastHealthCheck: number; + name: string; + shortId: string; + status: 'error' | 'mounted' | 'unmounted'; + type: 'directory' | 'nfs' | 'rclone' | 'sftp' | 'smb' | 'webdav'; + updatedAt: number; + }; }; export type UpdateVolumeResponse = UpdateVolumeResponses[keyof UpdateVolumeResponses]; export type MountVolumeData = { - body?: never; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/volumes/{shortId}/mount"; + body?: never; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/volumes/{shortId}/mount'; }; export type MountVolumeResponses = { - /** - * Volume mounted successfully - */ - 200: { - status: "error" | "mounted" | "unmounted"; - error?: string; - }; + /** + * Volume mounted successfully + */ + 200: { + status: 'error' | 'mounted' | 'unmounted'; + error?: string; + }; }; export type MountVolumeResponse = MountVolumeResponses[keyof MountVolumeResponses]; export type UnmountVolumeData = { - body?: never; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/volumes/{shortId}/unmount"; + body?: never; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/volumes/{shortId}/unmount'; }; export type UnmountVolumeResponses = { - /** - * Volume unmounted successfully - */ - 200: { - status: "error" | "mounted" | "unmounted"; - error?: string; - }; + /** + * Volume unmounted successfully + */ + 200: { + status: 'error' | 'mounted' | 'unmounted'; + error?: string; + }; }; export type UnmountVolumeResponse = UnmountVolumeResponses[keyof UnmountVolumeResponses]; export type HealthCheckVolumeData = { - body?: never; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/volumes/{shortId}/health-check"; + body?: never; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/volumes/{shortId}/health-check'; }; export type HealthCheckVolumeErrors = { - /** - * Volume not found - */ - 404: unknown; + /** + * Volume not found + */ + 404: unknown; }; export type HealthCheckVolumeResponses = { - /** - * Volume health check result - */ - 200: { - status: "error" | "mounted" | "unmounted"; - error?: string; - }; + /** + * Volume health check result + */ + 200: { + status: 'error' | 'mounted' | 'unmounted'; + error?: string; + }; }; export type HealthCheckVolumeResponse = HealthCheckVolumeResponses[keyof HealthCheckVolumeResponses]; export type ListFilesData = { - body?: never; - path: { - shortId: string; - }; - query?: { - limit?: string; - offset?: string; - path?: string; - }; - url: "/api/v1/volumes/{shortId}/files"; + body?: never; + path: { + shortId: string; + }; + query?: { + limit?: string; + offset?: string; + path?: string; + }; + url: '/api/v1/volumes/{shortId}/files'; }; export type ListFilesResponses = { - /** - * List of files in the volume - */ - 200: { - files: Array<{ - name: string; - path: string; - type: "directory" | "file"; - modifiedAt?: number; - size?: number; - }>; - hasMore: boolean; - limit: number; - offset: number; - path: string; - total: number; - }; + /** + * List of files in the volume + */ + 200: { + files: Array<{ + name: string; + path: string; + type: 'directory' | 'file'; + modifiedAt?: number; + size?: number; + }>; + hasMore: boolean; + limit: number; + offset: number; + path: string; + total: number; + }; }; export type ListFilesResponse = ListFilesResponses[keyof ListFilesResponses]; export type BrowseFilesystemData = { - body?: never; - path?: never; - query?: { - /** - * Directory path to browse (absolute path, defaults to /) - */ - path?: string; - }; - url: "/api/v1/volumes/filesystem/browse"; + body?: never; + path?: never; + query?: { + /** + * Directory path to browse (absolute path, defaults to /) + */ + path?: string; + }; + url: '/api/v1/volumes/filesystem/browse'; }; export type BrowseFilesystemResponses = { - /** - * List of directories in the specified path - */ - 200: { - directories: Array<{ - name: string; - path: string; - type: "directory" | "file"; - modifiedAt?: number; - size?: number; - }>; - path: string; - }; + /** + * List of directories in the specified path + */ + 200: { + directories: Array<{ + name: string; + path: string; + type: 'directory' | 'file'; + modifiedAt?: number; + size?: number; + }>; + path: string; + }; }; export type BrowseFilesystemResponse = BrowseFilesystemResponses[keyof BrowseFilesystemResponses]; export type ListRepositoriesData = { - body?: never; - path?: never; - query?: never; - url: "/api/v1/repositories"; + body?: never; + path?: never; + query?: never; + url: '/api/v1/repositories'; }; export type ListRepositoriesResponses = { - /** - * List of repositories - */ - 200: Array<{ - compressionMode: "auto" | "max" | "off" | null; - config: - | { - accessKeyId: string; - backend: "r2"; - bucket: string; - endpoint: string; - secretAccessKey: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - accessKeyId: string; - backend: "s3"; - bucket: string; - endpoint: string; - secretAccessKey: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - accountKey: string; - accountName: string; - backend: "azure"; - container: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - endpointSuffix?: string; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "gcs"; - bucket: string; - credentialsJson: string; - projectId: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "local"; - path: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "rclone"; - path: string; - remote: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "rest"; - url: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - password?: string; - path?: string; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - username?: string; - } - | { - backend: "sftp"; - host: string; - path: string; - privateKey: string; - user: string; - port?: number; - skipHostKeyCheck?: boolean; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - knownHosts?: string; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - }; - createdAt: number; - doctorResult: { - completedAt: number; - steps: Array<{ - error: string | null; - output: string | null; - step: string; - success: boolean; - }>; - success: boolean; - } | null; - id: string; - lastChecked: number | null; - lastError: string | null; - name: string; - shortId: string; - status: "cancelled" | "doctor" | "error" | "healthy" | "unknown" | null; - type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp"; - updatedAt: number; - }>; + /** + * List of repositories + */ + 200: Array<{ + compressionMode: 'auto' | 'max' | 'off' | null; + config: { + accessKeyId: string; + backend: 'r2'; + bucket: string; + endpoint: string; + secretAccessKey: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + accessKeyId: string; + backend: 's3'; + bucket: string; + endpoint: string; + secretAccessKey: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + accountKey: string; + accountName: string; + backend: 'azure'; + container: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + endpointSuffix?: string; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'gcs'; + bucket: string; + credentialsJson: string; + projectId: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'local'; + path: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'rclone'; + path: string; + remote: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'rest'; + url: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + password?: string; + path?: string; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + username?: string; + } | { + backend: 'sftp'; + host: string; + path: string; + privateKey: string; + user: string; + port?: number; + skipHostKeyCheck?: boolean; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + knownHosts?: string; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + }; + createdAt: number; + doctorResult: { + completedAt: number; + steps: Array<{ + error: string | null; + output: string | null; + step: string; + success: boolean; + }>; + success: boolean; + } | null; + id: string; + lastChecked: number | null; + lastError: string | null; + name: string; + shortId: string; + status: 'cancelled' | 'doctor' | 'error' | 'healthy' | 'unknown' | null; + type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3' | 'sftp'; + updatedAt: number; + }>; }; export type ListRepositoriesResponse = ListRepositoriesResponses[keyof ListRepositoriesResponses]; export type CreateRepositoryData = { - body?: { - config: - | { - accessKeyId: string; - backend: "r2"; - bucket: string; - endpoint: string; - secretAccessKey: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - accessKeyId: string; - backend: "s3"; - bucket: string; - endpoint: string; - secretAccessKey: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - accountKey: string; - accountName: string; - backend: "azure"; - container: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - endpointSuffix?: string; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "gcs"; - bucket: string; - credentialsJson: string; - projectId: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "local"; - path: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "rclone"; - path: string; - remote: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "rest"; - url: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - password?: string; - path?: string; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - username?: string; - } - | { - backend: "sftp"; - host: string; - path: string; - privateKey: string; - user: string; - port?: number; - skipHostKeyCheck?: boolean; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - knownHosts?: string; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - }; - name: string; - compressionMode?: "auto" | "max" | "off"; - }; - path?: never; - query?: never; - url: "/api/v1/repositories"; + body?: { + config: { + accessKeyId: string; + backend: 'r2'; + bucket: string; + endpoint: string; + secretAccessKey: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + accessKeyId: string; + backend: 's3'; + bucket: string; + endpoint: string; + secretAccessKey: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + accountKey: string; + accountName: string; + backend: 'azure'; + container: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + endpointSuffix?: string; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'gcs'; + bucket: string; + credentialsJson: string; + projectId: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'local'; + path: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'rclone'; + path: string; + remote: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'rest'; + url: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + password?: string; + path?: string; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + username?: string; + } | { + backend: 'sftp'; + host: string; + path: string; + privateKey: string; + user: string; + port?: number; + skipHostKeyCheck?: boolean; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + knownHosts?: string; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + }; + name: string; + compressionMode?: 'auto' | 'max' | 'off'; + }; + path?: never; + query?: never; + url: '/api/v1/repositories'; }; export type CreateRepositoryResponses = { - /** - * Repository created successfully - */ - 201: { - message: string; - repository: { - id: string; - name: string; - shortId: string; - }; - }; + /** + * Repository created successfully + */ + 201: { + message: string; + repository: { + id: string; + name: string; + shortId: string; + }; + }; }; export type CreateRepositoryResponse = CreateRepositoryResponses[keyof CreateRepositoryResponses]; export type ListRcloneRemotesData = { - body?: never; - path?: never; - query?: never; - url: "/api/v1/repositories/rclone-remotes"; + body?: never; + path?: never; + query?: never; + url: '/api/v1/repositories/rclone-remotes'; }; export type ListRcloneRemotesResponses = { - /** - * List of rclone remotes - */ - 200: Array<{ - name: string; - type: string; - }>; + /** + * List of rclone remotes + */ + 200: Array<{ + name: string; + type: string; + }>; }; export type ListRcloneRemotesResponse = ListRcloneRemotesResponses[keyof ListRcloneRemotesResponses]; export type DeleteRepositoryData = { - body?: never; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/repositories/{shortId}"; + body?: never; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/repositories/{shortId}'; }; export type DeleteRepositoryResponses = { - /** - * Repository deleted successfully - */ - 200: { - message: string; - }; + /** + * Repository deleted successfully + */ + 200: { + message: string; + }; }; export type DeleteRepositoryResponse = DeleteRepositoryResponses[keyof DeleteRepositoryResponses]; export type GetRepositoryData = { - body?: never; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/repositories/{shortId}"; + body?: never; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/repositories/{shortId}'; }; export type GetRepositoryResponses = { - /** - * Repository details - */ - 200: { - compressionMode: "auto" | "max" | "off" | null; - config: - | { - accessKeyId: string; - backend: "r2"; - bucket: string; - endpoint: string; - secretAccessKey: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - accessKeyId: string; - backend: "s3"; - bucket: string; - endpoint: string; - secretAccessKey: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - accountKey: string; - accountName: string; - backend: "azure"; - container: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - endpointSuffix?: string; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "gcs"; - bucket: string; - credentialsJson: string; - projectId: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "local"; - path: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "rclone"; - path: string; - remote: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "rest"; - url: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - password?: string; - path?: string; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - username?: string; - } - | { - backend: "sftp"; - host: string; - path: string; - privateKey: string; - user: string; - port?: number; - skipHostKeyCheck?: boolean; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - knownHosts?: string; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - }; - createdAt: number; - doctorResult: { - completedAt: number; - steps: Array<{ - error: string | null; - output: string | null; - step: string; - success: boolean; - }>; - success: boolean; - } | null; - id: string; - lastChecked: number | null; - lastError: string | null; - name: string; - shortId: string; - status: "cancelled" | "doctor" | "error" | "healthy" | "unknown" | null; - type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp"; - updatedAt: number; - }; + /** + * Repository details + */ + 200: { + compressionMode: 'auto' | 'max' | 'off' | null; + config: { + accessKeyId: string; + backend: 'r2'; + bucket: string; + endpoint: string; + secretAccessKey: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + accessKeyId: string; + backend: 's3'; + bucket: string; + endpoint: string; + secretAccessKey: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + accountKey: string; + accountName: string; + backend: 'azure'; + container: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + endpointSuffix?: string; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'gcs'; + bucket: string; + credentialsJson: string; + projectId: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'local'; + path: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'rclone'; + path: string; + remote: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'rest'; + url: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + password?: string; + path?: string; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + username?: string; + } | { + backend: 'sftp'; + host: string; + path: string; + privateKey: string; + user: string; + port?: number; + skipHostKeyCheck?: boolean; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + knownHosts?: string; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + }; + createdAt: number; + doctorResult: { + completedAt: number; + steps: Array<{ + error: string | null; + output: string | null; + step: string; + success: boolean; + }>; + success: boolean; + } | null; + id: string; + lastChecked: number | null; + lastError: string | null; + name: string; + shortId: string; + status: 'cancelled' | 'doctor' | 'error' | 'healthy' | 'unknown' | null; + type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3' | 'sftp'; + updatedAt: number; + }; }; export type GetRepositoryResponse = GetRepositoryResponses[keyof GetRepositoryResponses]; export type UpdateRepositoryData = { - body?: { - compressionMode?: "auto" | "max" | "off"; - config?: - | { - accessKeyId: string; - backend: "r2"; - bucket: string; - endpoint: string; - secretAccessKey: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - accessKeyId: string; - backend: "s3"; - bucket: string; - endpoint: string; - secretAccessKey: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - accountKey: string; - accountName: string; - backend: "azure"; - container: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - endpointSuffix?: string; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "gcs"; - bucket: string; - credentialsJson: string; - projectId: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "local"; - path: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "rclone"; - path: string; - remote: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "rest"; - url: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - password?: string; - path?: string; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - username?: string; - } - | { - backend: "sftp"; - host: string; - path: string; - privateKey: string; - user: string; - port?: number; - skipHostKeyCheck?: boolean; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - knownHosts?: string; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - }; - name?: string; - }; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/repositories/{shortId}"; + body?: { + compressionMode?: 'auto' | 'max' | 'off'; + config?: { + accessKeyId: string; + backend: 'r2'; + bucket: string; + endpoint: string; + secretAccessKey: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + accessKeyId: string; + backend: 's3'; + bucket: string; + endpoint: string; + secretAccessKey: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + accountKey: string; + accountName: string; + backend: 'azure'; + container: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + endpointSuffix?: string; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'gcs'; + bucket: string; + credentialsJson: string; + projectId: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'local'; + path: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'rclone'; + path: string; + remote: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'rest'; + url: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + password?: string; + path?: string; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + username?: string; + } | { + backend: 'sftp'; + host: string; + path: string; + privateKey: string; + user: string; + port?: number; + skipHostKeyCheck?: boolean; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + knownHosts?: string; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + }; + name?: string; + }; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/repositories/{shortId}'; }; export type UpdateRepositoryErrors = { - /** - * Invalid repository update payload - */ - 400: unknown; - /** - * Repository not found - */ - 404: unknown; - /** - * Repository with this name already exists - */ - 409: unknown; + /** + * Invalid repository update payload + */ + 400: unknown; + /** + * Repository not found + */ + 404: unknown; + /** + * Repository with this name already exists + */ + 409: unknown; }; export type UpdateRepositoryResponses = { - /** - * Repository updated successfully - */ - 200: { - compressionMode: "auto" | "max" | "off" | null; - config: - | { - accessKeyId: string; - backend: "r2"; - bucket: string; - endpoint: string; - secretAccessKey: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - accessKeyId: string; - backend: "s3"; - bucket: string; - endpoint: string; - secretAccessKey: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - accountKey: string; - accountName: string; - backend: "azure"; - container: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - endpointSuffix?: string; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "gcs"; - bucket: string; - credentialsJson: string; - projectId: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "local"; - path: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "rclone"; - path: string; - remote: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "rest"; - url: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - password?: string; - path?: string; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - username?: string; - } - | { - backend: "sftp"; - host: string; - path: string; - privateKey: string; - user: string; - port?: number; - skipHostKeyCheck?: boolean; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - knownHosts?: string; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - }; - createdAt: number; - doctorResult: { - completedAt: number; - steps: Array<{ - error: string | null; - output: string | null; - step: string; - success: boolean; - }>; - success: boolean; - } | null; - id: string; - lastChecked: number | null; - lastError: string | null; - name: string; - shortId: string; - status: "cancelled" | "doctor" | "error" | "healthy" | "unknown" | null; - type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp"; - updatedAt: number; - }; + /** + * Repository updated successfully + */ + 200: { + compressionMode: 'auto' | 'max' | 'off' | null; + config: { + accessKeyId: string; + backend: 'r2'; + bucket: string; + endpoint: string; + secretAccessKey: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + accessKeyId: string; + backend: 's3'; + bucket: string; + endpoint: string; + secretAccessKey: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + accountKey: string; + accountName: string; + backend: 'azure'; + container: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + endpointSuffix?: string; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'gcs'; + bucket: string; + credentialsJson: string; + projectId: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'local'; + path: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'rclone'; + path: string; + remote: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'rest'; + url: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + password?: string; + path?: string; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + username?: string; + } | { + backend: 'sftp'; + host: string; + path: string; + privateKey: string; + user: string; + port?: number; + skipHostKeyCheck?: boolean; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + knownHosts?: string; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + }; + createdAt: number; + doctorResult: { + completedAt: number; + steps: Array<{ + error: string | null; + output: string | null; + step: string; + success: boolean; + }>; + success: boolean; + } | null; + id: string; + lastChecked: number | null; + lastError: string | null; + name: string; + shortId: string; + status: 'cancelled' | 'doctor' | 'error' | 'healthy' | 'unknown' | null; + type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3' | 'sftp'; + updatedAt: number; + }; }; export type UpdateRepositoryResponse = UpdateRepositoryResponses[keyof UpdateRepositoryResponses]; export type GetRepositoryStatsData = { - body?: never; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/repositories/{shortId}/stats"; + body?: never; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/repositories/{shortId}/stats'; }; export type GetRepositoryStatsResponses = { - /** - * Repository statistics - */ - 200: { - compression_progress?: number; - compression_ratio?: number; - compression_space_saving?: number; - snapshots_count?: number; - total_size?: number; - total_uncompressed_size?: number; - }; + /** + * Repository statistics + */ + 200: { + compression_progress?: number; + compression_ratio?: number; + compression_space_saving?: number; + snapshots_count?: number; + total_size?: number; + total_uncompressed_size?: number; + }; }; export type GetRepositoryStatsResponse = GetRepositoryStatsResponses[keyof GetRepositoryStatsResponses]; export type DeleteSnapshotsData = { - body?: { - snapshotIds: Array; - }; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/repositories/{shortId}/snapshots"; + body?: { + snapshotIds: Array; + }; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/repositories/{shortId}/snapshots'; }; export type DeleteSnapshotsResponses = { - /** - * Snapshots deleted successfully - */ - 200: { - message: string; - }; + /** + * Snapshots deleted successfully + */ + 200: { + message: string; + }; }; export type DeleteSnapshotsResponse = DeleteSnapshotsResponses[keyof DeleteSnapshotsResponses]; export type ListSnapshotsData = { - body?: never; - path: { - shortId: string; - }; - query?: { - backupId?: string; - }; - url: "/api/v1/repositories/{shortId}/snapshots"; + body?: never; + path: { + shortId: string; + }; + query?: { + backupId?: string; + }; + url: '/api/v1/repositories/{shortId}/snapshots'; }; export type ListSnapshotsResponses = { - /** - * List of snapshots - */ - 200: Array<{ - duration: number; - paths: Array; - retentionCategories: Array; - short_id: string; - size: number; - tags: Array; - time: number; - hostname?: string; - summary?: { - backup_end: string; - backup_start: string; - data_added: number; - data_blobs: number; - dirs_changed: number; - dirs_new: number; - dirs_unmodified: number; - files_changed: number; - files_new: number; - files_unmodified: number; - total_bytes_processed: number; - total_files_processed: number; - tree_blobs: number; - data_added_packed?: number; - }; - }>; + /** + * List of snapshots + */ + 200: Array<{ + duration: number; + paths: Array; + retentionCategories: Array; + short_id: string; + size: number; + tags: Array; + time: number; + hostname?: string; + summary?: { + backup_end: string; + backup_start: string; + data_added: number; + data_blobs: number; + dirs_changed: number; + dirs_new: number; + dirs_unmodified: number; + files_changed: number; + files_new: number; + files_unmodified: number; + total_bytes_processed: number; + total_files_processed: number; + tree_blobs: number; + data_added_packed?: number; + }; + }>; }; export type ListSnapshotsResponse = ListSnapshotsResponses[keyof ListSnapshotsResponses]; export type RefreshSnapshotsData = { - body?: never; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/repositories/{shortId}/snapshots/refresh"; + body?: never; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/repositories/{shortId}/snapshots/refresh'; }; export type RefreshSnapshotsResponses = { - /** - * Snapshot cache cleared and refreshed - */ - 200: { - count: number; - message: string; - }; + /** + * Snapshot cache cleared and refreshed + */ + 200: { + count: number; + message: string; + }; }; export type RefreshSnapshotsResponse = RefreshSnapshotsResponses[keyof RefreshSnapshotsResponses]; export type DeleteSnapshotData = { - body?: never; - path: { - shortId: string; - snapshotId: string; - }; - query?: never; - url: "/api/v1/repositories/{shortId}/snapshots/{snapshotId}"; + body?: never; + path: { + shortId: string; + snapshotId: string; + }; + query?: never; + url: '/api/v1/repositories/{shortId}/snapshots/{snapshotId}'; }; export type DeleteSnapshotResponses = { - /** - * Snapshot deleted successfully - */ - 200: { - message: string; - }; + /** + * Snapshot deleted successfully + */ + 200: { + message: string; + }; }; export type DeleteSnapshotResponse = DeleteSnapshotResponses[keyof DeleteSnapshotResponses]; export type GetSnapshotDetailsData = { - body?: never; - path: { - shortId: string; - snapshotId: string; - }; - query?: never; - url: "/api/v1/repositories/{shortId}/snapshots/{snapshotId}"; + body?: never; + path: { + shortId: string; + snapshotId: string; + }; + query?: never; + url: '/api/v1/repositories/{shortId}/snapshots/{snapshotId}'; }; export type GetSnapshotDetailsResponses = { - /** - * Snapshot details - */ - 200: { - duration: number; - paths: Array; - retentionCategories: Array; - short_id: string; - size: number; - tags: Array; - time: number; - hostname?: string; - summary?: { - backup_end: string; - backup_start: string; - data_added: number; - data_blobs: number; - dirs_changed: number; - dirs_new: number; - dirs_unmodified: number; - files_changed: number; - files_new: number; - files_unmodified: number; - total_bytes_processed: number; - total_files_processed: number; - tree_blobs: number; - data_added_packed?: number; - }; - }; + /** + * Snapshot details + */ + 200: { + duration: number; + paths: Array; + retentionCategories: Array; + short_id: string; + size: number; + tags: Array; + time: number; + hostname?: string; + summary?: { + backup_end: string; + backup_start: string; + data_added: number; + data_blobs: number; + dirs_changed: number; + dirs_new: number; + dirs_unmodified: number; + files_changed: number; + files_new: number; + files_unmodified: number; + total_bytes_processed: number; + total_files_processed: number; + tree_blobs: number; + data_added_packed?: number; + }; + }; }; export type GetSnapshotDetailsResponse = GetSnapshotDetailsResponses[keyof GetSnapshotDetailsResponses]; export type ListSnapshotFilesData = { - body?: never; - path: { - shortId: string; - snapshotId: string; - }; - query?: { - limit?: string; - offset?: string; - path?: string; - }; - url: "/api/v1/repositories/{shortId}/snapshots/{snapshotId}/files"; + body?: never; + path: { + shortId: string; + snapshotId: string; + }; + query?: { + limit?: string; + offset?: string; + path?: string; + }; + url: '/api/v1/repositories/{shortId}/snapshots/{snapshotId}/files'; }; export type ListSnapshotFilesResponses = { - /** - * List of files and directories in the snapshot - */ - 200: { - files: Array<{ - name: string; - path: string; - type: string; - atime?: string; - ctime?: string; - gid?: number; - mode?: number; - mtime?: string; - size?: number; - uid?: number; - }>; - hasMore: boolean; - limit: number; - offset: number; - snapshot: { - hostname: string; - id: string; - paths: Array; - short_id: string; - time: string; - }; - total: number; - }; + /** + * List of files and directories in the snapshot + */ + 200: { + files: Array<{ + name: string; + path: string; + type: string; + atime?: string; + ctime?: string; + gid?: number; + mode?: number; + mtime?: string; + size?: number; + uid?: number; + }>; + hasMore: boolean; + limit: number; + offset: number; + snapshot: { + hostname: string; + id: string; + paths: Array; + short_id: string; + time: string; + }; + total: number; + }; }; export type ListSnapshotFilesResponse = ListSnapshotFilesResponses[keyof ListSnapshotFilesResponses]; export type DumpSnapshotData = { - body?: never; - path: { - shortId: string; - snapshotId: string; - }; - query?: { - kind?: "dir" | "file"; - path?: string; - }; - url: "/api/v1/repositories/{shortId}/snapshots/{snapshotId}/dump"; + body?: never; + path: { + shortId: string; + snapshotId: string; + }; + query?: { + kind?: 'dir' | 'file'; + path?: string; + }; + url: '/api/v1/repositories/{shortId}/snapshots/{snapshotId}/dump'; }; export type DumpSnapshotResponses = { - /** - * Snapshot content stream - */ - 200: Blob | File; + /** + * Snapshot content stream + */ + 200: Blob | File; }; export type DumpSnapshotResponse = DumpSnapshotResponses[keyof DumpSnapshotResponses]; export type RestoreSnapshotData = { - body?: { - snapshotId: string; - delete?: boolean; - exclude?: Array; - excludeXattr?: Array; - include?: Array; - overwrite?: "always" | "if-changed" | "if-newer" | "never"; - targetPath?: string; - }; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/repositories/{shortId}/restore"; + body?: { + snapshotId: string; + delete?: boolean; + exclude?: Array; + excludeXattr?: Array; + include?: Array; + overwrite?: 'always' | 'if-changed' | 'if-newer' | 'never'; + targetPath?: string; + }; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/repositories/{shortId}/restore'; }; export type RestoreSnapshotResponses = { - /** - * Snapshot restored successfully - */ - 200: { - filesRestored: number; - filesSkipped: number; - message: string; - success: boolean; - }; + /** + * Snapshot restored successfully + */ + 200: { + filesRestored: number; + filesSkipped: number; + message: string; + success: boolean; + }; }; export type RestoreSnapshotResponse = RestoreSnapshotResponses[keyof RestoreSnapshotResponses]; export type CancelDoctorData = { - body?: never; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/repositories/{shortId}/doctor"; + body?: never; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/repositories/{shortId}/doctor'; }; export type CancelDoctorErrors = { - /** - * No doctor operation is currently running - */ - 409: unknown; + /** + * No doctor operation is currently running + */ + 409: unknown; }; export type CancelDoctorResponses = { - /** - * Doctor operation cancelled - */ - 200: { - message: string; - }; + /** + * Doctor operation cancelled + */ + 200: { + message: string; + }; }; export type CancelDoctorResponse = CancelDoctorResponses[keyof CancelDoctorResponses]; export type StartDoctorData = { - body?: never; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/repositories/{shortId}/doctor"; + body?: never; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/repositories/{shortId}/doctor'; }; export type StartDoctorErrors = { - /** - * Doctor operation already in progress - */ - 409: unknown; + /** + * Doctor operation already in progress + */ + 409: unknown; }; export type StartDoctorResponses = { - /** - * Doctor operation started - */ - 202: { - message: string; - repositoryId: string; - }; + /** + * Doctor operation started + */ + 202: { + message: string; + repositoryId: string; + }; }; export type StartDoctorResponse = StartDoctorResponses[keyof StartDoctorResponses]; export type UnlockRepositoryData = { - body?: never; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/repositories/{shortId}/unlock"; + body?: never; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/repositories/{shortId}/unlock'; }; export type UnlockRepositoryResponses = { - /** - * Repository unlocked successfully - */ - 200: { - message: string; - success: boolean; - }; + /** + * Repository unlocked successfully + */ + 200: { + message: string; + success: boolean; + }; }; export type UnlockRepositoryResponse = UnlockRepositoryResponses[keyof UnlockRepositoryResponses]; export type TagSnapshotsData = { - body?: { - snapshotIds: Array; - add?: Array; - remove?: Array; - set?: Array; - }; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/repositories/{shortId}/snapshots/tag"; + body?: { + snapshotIds: Array; + add?: Array; + remove?: Array; + set?: Array; + }; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/repositories/{shortId}/snapshots/tag'; }; export type TagSnapshotsResponses = { - /** - * Snapshots tagged successfully - */ - 200: { - message: string; - }; + /** + * Snapshots tagged successfully + */ + 200: { + message: string; + }; }; export type TagSnapshotsResponse = TagSnapshotsResponses[keyof TagSnapshotsResponses]; export type DevPanelExecData = { - body?: { - command: string; - args?: Array; - }; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/repositories/{shortId}/exec"; + body?: { + command: string; + args?: Array; + }; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/repositories/{shortId}/exec'; }; export type DevPanelExecErrors = { - /** - * Dev panel not enabled - */ - 403: unknown; + /** + * Dev panel not enabled + */ + 403: unknown; }; export type DevPanelExecResponses = { - /** - * Command output stream (SSE) - */ - 200: string; + /** + * Command output stream (SSE) + */ + 200: string; }; export type DevPanelExecResponse = DevPanelExecResponses[keyof DevPanelExecResponses]; export type ListBackupSchedulesData = { - body?: never; - path?: never; - query?: never; - url: "/api/v1/backups"; + body?: never; + path?: never; + query?: never; + url: '/api/v1/backups'; }; export type ListBackupSchedulesResponses = { - /** - * List of backup schedules - */ - 200: Array<{ - createdAt: number; - cronExpression: string; - enabled: boolean; - excludeIfPresent: Array | null; - excludePatterns: Array | null; - id: number; - includePatterns: Array | null; - lastBackupAt: number | null; - lastBackupError: string | null; - lastBackupStatus: "error" | "in_progress" | "success" | "warning" | null; - name: string; - nextBackupAt: number | null; - oneFileSystem: boolean; - repository: { - compressionMode: "auto" | "max" | "off" | null; - config: - | { - accessKeyId: string; - backend: "r2"; - bucket: string; - endpoint: string; - secretAccessKey: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - accessKeyId: string; - backend: "s3"; - bucket: string; - endpoint: string; - secretAccessKey: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - accountKey: string; - accountName: string; - backend: "azure"; - container: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - endpointSuffix?: string; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "gcs"; - bucket: string; - credentialsJson: string; - projectId: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "local"; - path: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "rclone"; - path: string; - remote: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "rest"; - url: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - password?: string; - path?: string; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - username?: string; - } - | { - backend: "sftp"; - host: string; - path: string; - privateKey: string; - user: string; - port?: number; - skipHostKeyCheck?: boolean; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - knownHosts?: string; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - }; - createdAt: number; - doctorResult: { - completedAt: number; - steps: Array<{ - error: string | null; - output: string | null; - step: string; - success: boolean; - }>; - success: boolean; - } | null; - id: string; - lastChecked: number | null; - lastError: string | null; - name: string; - shortId: string; - status: "cancelled" | "doctor" | "error" | "healthy" | "unknown" | null; - type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp"; - updatedAt: number; - }; - repositoryId: string; - retentionPolicy: { - keepDaily?: number; - keepHourly?: number; - keepLast?: number; - keepMonthly?: number; - keepWeekly?: number; - keepWithinDuration?: string; - keepYearly?: number; - } | null; - shortId: string; - updatedAt: number; - volume: { - autoRemount: boolean; - config: - | { - backend: "directory"; - path: string; - readOnly?: false; - } - | { - backend: "nfs"; - exportPath: string; - server: string; - version: "3" | "4" | "4.1"; - port?: number; - readOnly?: boolean; - } - | { - backend: "rclone"; - path: string; - remote: string; - readOnly?: boolean; - } - | { - backend: "sftp"; - host: string; - path: string; - username: string; - port?: number; - skipHostKeyCheck?: boolean; - knownHosts?: string; - password?: string; - privateKey?: string; - readOnly?: boolean; - } - | { - backend: "smb"; - server: string; - share: string; - vers?: "1.0" | "2.0" | "2.1" | "3.0" | "auto"; - port?: number; - domain?: string; - guest?: boolean; - password?: string; - readOnly?: boolean; - username?: string; - } - | { - backend: "webdav"; - path: string; - server: string; - port?: number; - password?: string; - readOnly?: boolean; - ssl?: boolean; - username?: string; - }; - createdAt: number; - id: number; - lastError: string | null; - lastHealthCheck: number; - name: string; - shortId: string; - status: "error" | "mounted" | "unmounted"; - type: "directory" | "nfs" | "rclone" | "sftp" | "smb" | "webdav"; - updatedAt: number; - }; - volumeId: number; - }>; + /** + * List of backup schedules + */ + 200: Array<{ + createdAt: number; + cronExpression: string; + enabled: boolean; + excludeIfPresent: Array | null; + excludePatterns: Array | null; + id: number; + includePatterns: Array | null; + lastBackupAt: number | null; + lastBackupError: string | null; + lastBackupStatus: 'error' | 'in_progress' | 'success' | 'warning' | null; + name: string; + nextBackupAt: number | null; + oneFileSystem: boolean; + repository: { + compressionMode: 'auto' | 'max' | 'off' | null; + config: { + accessKeyId: string; + backend: 'r2'; + bucket: string; + endpoint: string; + secretAccessKey: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + accessKeyId: string; + backend: 's3'; + bucket: string; + endpoint: string; + secretAccessKey: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + accountKey: string; + accountName: string; + backend: 'azure'; + container: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + endpointSuffix?: string; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'gcs'; + bucket: string; + credentialsJson: string; + projectId: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'local'; + path: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'rclone'; + path: string; + remote: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'rest'; + url: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + password?: string; + path?: string; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + username?: string; + } | { + backend: 'sftp'; + host: string; + path: string; + privateKey: string; + user: string; + port?: number; + skipHostKeyCheck?: boolean; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + knownHosts?: string; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + }; + createdAt: number; + doctorResult: { + completedAt: number; + steps: Array<{ + error: string | null; + output: string | null; + step: string; + success: boolean; + }>; + success: boolean; + } | null; + id: string; + lastChecked: number | null; + lastError: string | null; + name: string; + shortId: string; + status: 'cancelled' | 'doctor' | 'error' | 'healthy' | 'unknown' | null; + type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3' | 'sftp'; + updatedAt: number; + }; + repositoryId: string; + retentionPolicy: { + keepDaily?: number; + keepHourly?: number; + keepLast?: number; + keepMonthly?: number; + keepWeekly?: number; + keepWithinDuration?: string; + keepYearly?: number; + } | null; + shortId: string; + updatedAt: number; + volume: { + autoRemount: boolean; + config: { + backend: 'directory'; + path: string; + readOnly?: false; + } | { + backend: 'nfs'; + exportPath: string; + server: string; + version: '3' | '4' | '4.1'; + port?: number; + readOnly?: boolean; + } | { + backend: 'rclone'; + path: string; + remote: string; + readOnly?: boolean; + } | { + backend: 'sftp'; + host: string; + path: string; + username: string; + port?: number; + skipHostKeyCheck?: boolean; + knownHosts?: string; + password?: string; + privateKey?: string; + readOnly?: boolean; + } | { + backend: 'smb'; + server: string; + share: string; + vers?: '1.0' | '2.0' | '2.1' | '3.0' | 'auto'; + port?: number; + domain?: string; + guest?: boolean; + password?: string; + readOnly?: boolean; + username?: string; + } | { + backend: 'webdav'; + path: string; + server: string; + port?: number; + password?: string; + readOnly?: boolean; + ssl?: boolean; + username?: string; + }; + createdAt: number; + id: number; + lastError: string | null; + lastHealthCheck: number; + name: string; + shortId: string; + status: 'error' | 'mounted' | 'unmounted'; + type: 'directory' | 'nfs' | 'rclone' | 'sftp' | 'smb' | 'webdav'; + updatedAt: number; + }; + volumeId: number; + }>; }; export type ListBackupSchedulesResponse = ListBackupSchedulesResponses[keyof ListBackupSchedulesResponses]; export type CreateBackupScheduleData = { - body?: { - cronExpression: string; - enabled: boolean; - name: string; - repositoryId: string; - volumeId: number | string; - excludeIfPresent?: Array; - excludePatterns?: Array; - includePatterns?: Array; - oneFileSystem?: boolean; - retentionPolicy?: { - keepDaily?: number; - keepHourly?: number; - keepLast?: number; - keepMonthly?: number; - keepWeekly?: number; - keepWithinDuration?: string; - keepYearly?: number; - }; - tags?: Array; - }; - path?: never; - query?: never; - url: "/api/v1/backups"; + body?: { + cronExpression: string; + enabled: boolean; + name: string; + repositoryId: string; + volumeId: number | string; + excludeIfPresent?: Array; + excludePatterns?: Array; + includePatterns?: Array; + oneFileSystem?: boolean; + retentionPolicy?: { + keepDaily?: number; + keepHourly?: number; + keepLast?: number; + keepMonthly?: number; + keepWeekly?: number; + keepWithinDuration?: string; + keepYearly?: number; + }; + tags?: Array; + }; + path?: never; + query?: never; + url: '/api/v1/backups'; }; export type CreateBackupScheduleResponses = { - /** - * Backup schedule created successfully - */ - 201: { - createdAt: number; - cronExpression: string; - enabled: boolean; - excludeIfPresent: Array | null; - excludePatterns: Array | null; - id: number; - includePatterns: Array | null; - lastBackupAt: number | null; - lastBackupError: string | null; - lastBackupStatus: "error" | "in_progress" | "success" | "warning" | null; - name: string; - nextBackupAt: number | null; - oneFileSystem: boolean; - repositoryId: string; - retentionPolicy: { - keepDaily?: number; - keepHourly?: number; - keepLast?: number; - keepMonthly?: number; - keepWeekly?: number; - keepWithinDuration?: string; - keepYearly?: number; - } | null; - shortId: string; - updatedAt: number; - volumeId: number; - }; + /** + * Backup schedule created successfully + */ + 201: { + createdAt: number; + cronExpression: string; + enabled: boolean; + excludeIfPresent: Array | null; + excludePatterns: Array | null; + id: number; + includePatterns: Array | null; + lastBackupAt: number | null; + lastBackupError: string | null; + lastBackupStatus: 'error' | 'in_progress' | 'success' | 'warning' | null; + name: string; + nextBackupAt: number | null; + oneFileSystem: boolean; + repositoryId: string; + retentionPolicy: { + keepDaily?: number; + keepHourly?: number; + keepLast?: number; + keepMonthly?: number; + keepWeekly?: number; + keepWithinDuration?: string; + keepYearly?: number; + } | null; + shortId: string; + updatedAt: number; + volumeId: number; + }; }; export type CreateBackupScheduleResponse = CreateBackupScheduleResponses[keyof CreateBackupScheduleResponses]; export type DeleteBackupScheduleData = { - body?: never; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/backups/{shortId}"; + body?: never; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/backups/{shortId}'; }; export type DeleteBackupScheduleResponses = { - /** - * Backup schedule deleted successfully - */ - 200: { - success: boolean; - }; + /** + * Backup schedule deleted successfully + */ + 200: { + success: boolean; + }; }; export type DeleteBackupScheduleResponse = DeleteBackupScheduleResponses[keyof DeleteBackupScheduleResponses]; export type GetBackupScheduleData = { - body?: never; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/backups/{shortId}"; + body?: never; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/backups/{shortId}'; }; export type GetBackupScheduleResponses = { - /** - * Backup schedule details - */ - 200: { - createdAt: number; - cronExpression: string; - enabled: boolean; - excludeIfPresent: Array | null; - excludePatterns: Array | null; - id: number; - includePatterns: Array | null; - lastBackupAt: number | null; - lastBackupError: string | null; - lastBackupStatus: "error" | "in_progress" | "success" | "warning" | null; - name: string; - nextBackupAt: number | null; - oneFileSystem: boolean; - repository: { - compressionMode: "auto" | "max" | "off" | null; - config: - | { - accessKeyId: string; - backend: "r2"; - bucket: string; - endpoint: string; - secretAccessKey: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - accessKeyId: string; - backend: "s3"; - bucket: string; - endpoint: string; - secretAccessKey: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - accountKey: string; - accountName: string; - backend: "azure"; - container: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - endpointSuffix?: string; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "gcs"; - bucket: string; - credentialsJson: string; - projectId: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "local"; - path: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "rclone"; - path: string; - remote: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "rest"; - url: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - password?: string; - path?: string; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - username?: string; - } - | { - backend: "sftp"; - host: string; - path: string; - privateKey: string; - user: string; - port?: number; - skipHostKeyCheck?: boolean; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - knownHosts?: string; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - }; - createdAt: number; - doctorResult: { - completedAt: number; - steps: Array<{ - error: string | null; - output: string | null; - step: string; - success: boolean; - }>; - success: boolean; - } | null; - id: string; - lastChecked: number | null; - lastError: string | null; - name: string; - shortId: string; - status: "cancelled" | "doctor" | "error" | "healthy" | "unknown" | null; - type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp"; - updatedAt: number; - }; - repositoryId: string; - retentionPolicy: { - keepDaily?: number; - keepHourly?: number; - keepLast?: number; - keepMonthly?: number; - keepWeekly?: number; - keepWithinDuration?: string; - keepYearly?: number; - } | null; - shortId: string; - updatedAt: number; - volume: { - autoRemount: boolean; - config: - | { - backend: "directory"; - path: string; - readOnly?: false; - } - | { - backend: "nfs"; - exportPath: string; - server: string; - version: "3" | "4" | "4.1"; - port?: number; - readOnly?: boolean; - } - | { - backend: "rclone"; - path: string; - remote: string; - readOnly?: boolean; - } - | { - backend: "sftp"; - host: string; - path: string; - username: string; - port?: number; - skipHostKeyCheck?: boolean; - knownHosts?: string; - password?: string; - privateKey?: string; - readOnly?: boolean; - } - | { - backend: "smb"; - server: string; - share: string; - vers?: "1.0" | "2.0" | "2.1" | "3.0" | "auto"; - port?: number; - domain?: string; - guest?: boolean; - password?: string; - readOnly?: boolean; - username?: string; - } - | { - backend: "webdav"; - path: string; - server: string; - port?: number; - password?: string; - readOnly?: boolean; - ssl?: boolean; - username?: string; - }; - createdAt: number; - id: number; - lastError: string | null; - lastHealthCheck: number; - name: string; - shortId: string; - status: "error" | "mounted" | "unmounted"; - type: "directory" | "nfs" | "rclone" | "sftp" | "smb" | "webdav"; - updatedAt: number; - }; - volumeId: number; - }; + /** + * Backup schedule details + */ + 200: { + createdAt: number; + cronExpression: string; + enabled: boolean; + excludeIfPresent: Array | null; + excludePatterns: Array | null; + id: number; + includePatterns: Array | null; + lastBackupAt: number | null; + lastBackupError: string | null; + lastBackupStatus: 'error' | 'in_progress' | 'success' | 'warning' | null; + name: string; + nextBackupAt: number | null; + oneFileSystem: boolean; + repository: { + compressionMode: 'auto' | 'max' | 'off' | null; + config: { + accessKeyId: string; + backend: 'r2'; + bucket: string; + endpoint: string; + secretAccessKey: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + accessKeyId: string; + backend: 's3'; + bucket: string; + endpoint: string; + secretAccessKey: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + accountKey: string; + accountName: string; + backend: 'azure'; + container: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + endpointSuffix?: string; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'gcs'; + bucket: string; + credentialsJson: string; + projectId: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'local'; + path: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'rclone'; + path: string; + remote: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'rest'; + url: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + password?: string; + path?: string; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + username?: string; + } | { + backend: 'sftp'; + host: string; + path: string; + privateKey: string; + user: string; + port?: number; + skipHostKeyCheck?: boolean; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + knownHosts?: string; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + }; + createdAt: number; + doctorResult: { + completedAt: number; + steps: Array<{ + error: string | null; + output: string | null; + step: string; + success: boolean; + }>; + success: boolean; + } | null; + id: string; + lastChecked: number | null; + lastError: string | null; + name: string; + shortId: string; + status: 'cancelled' | 'doctor' | 'error' | 'healthy' | 'unknown' | null; + type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3' | 'sftp'; + updatedAt: number; + }; + repositoryId: string; + retentionPolicy: { + keepDaily?: number; + keepHourly?: number; + keepLast?: number; + keepMonthly?: number; + keepWeekly?: number; + keepWithinDuration?: string; + keepYearly?: number; + } | null; + shortId: string; + updatedAt: number; + volume: { + autoRemount: boolean; + config: { + backend: 'directory'; + path: string; + readOnly?: false; + } | { + backend: 'nfs'; + exportPath: string; + server: string; + version: '3' | '4' | '4.1'; + port?: number; + readOnly?: boolean; + } | { + backend: 'rclone'; + path: string; + remote: string; + readOnly?: boolean; + } | { + backend: 'sftp'; + host: string; + path: string; + username: string; + port?: number; + skipHostKeyCheck?: boolean; + knownHosts?: string; + password?: string; + privateKey?: string; + readOnly?: boolean; + } | { + backend: 'smb'; + server: string; + share: string; + vers?: '1.0' | '2.0' | '2.1' | '3.0' | 'auto'; + port?: number; + domain?: string; + guest?: boolean; + password?: string; + readOnly?: boolean; + username?: string; + } | { + backend: 'webdav'; + path: string; + server: string; + port?: number; + password?: string; + readOnly?: boolean; + ssl?: boolean; + username?: string; + }; + createdAt: number; + id: number; + lastError: string | null; + lastHealthCheck: number; + name: string; + shortId: string; + status: 'error' | 'mounted' | 'unmounted'; + type: 'directory' | 'nfs' | 'rclone' | 'sftp' | 'smb' | 'webdav'; + updatedAt: number; + }; + volumeId: number; + }; }; export type GetBackupScheduleResponse = GetBackupScheduleResponses[keyof GetBackupScheduleResponses]; export type UpdateBackupScheduleData = { - body?: { - cronExpression: string; - repositoryId: string; - enabled?: boolean; - excludeIfPresent?: Array; - excludePatterns?: Array; - includePatterns?: Array; - name?: string; - oneFileSystem?: boolean; - retentionPolicy?: { - keepDaily?: number; - keepHourly?: number; - keepLast?: number; - keepMonthly?: number; - keepWeekly?: number; - keepWithinDuration?: string; - keepYearly?: number; - }; - tags?: Array; - }; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/backups/{shortId}"; + body?: { + cronExpression: string; + repositoryId: string; + enabled?: boolean; + excludeIfPresent?: Array; + excludePatterns?: Array; + includePatterns?: Array; + name?: string; + oneFileSystem?: boolean; + retentionPolicy?: { + keepDaily?: number; + keepHourly?: number; + keepLast?: number; + keepMonthly?: number; + keepWeekly?: number; + keepWithinDuration?: string; + keepYearly?: number; + }; + tags?: Array; + }; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/backups/{shortId}'; }; export type UpdateBackupScheduleResponses = { - /** - * Backup schedule updated successfully - */ - 200: { - createdAt: number; - cronExpression: string; - enabled: boolean; - excludeIfPresent: Array | null; - excludePatterns: Array | null; - id: number; - includePatterns: Array | null; - lastBackupAt: number | null; - lastBackupError: string | null; - lastBackupStatus: "error" | "in_progress" | "success" | "warning" | null; - name: string; - nextBackupAt: number | null; - oneFileSystem: boolean; - repositoryId: string; - retentionPolicy: { - keepDaily?: number; - keepHourly?: number; - keepLast?: number; - keepMonthly?: number; - keepWeekly?: number; - keepWithinDuration?: string; - keepYearly?: number; - } | null; - shortId: string; - updatedAt: number; - volumeId: number; - }; + /** + * Backup schedule updated successfully + */ + 200: { + createdAt: number; + cronExpression: string; + enabled: boolean; + excludeIfPresent: Array | null; + excludePatterns: Array | null; + id: number; + includePatterns: Array | null; + lastBackupAt: number | null; + lastBackupError: string | null; + lastBackupStatus: 'error' | 'in_progress' | 'success' | 'warning' | null; + name: string; + nextBackupAt: number | null; + oneFileSystem: boolean; + repositoryId: string; + retentionPolicy: { + keepDaily?: number; + keepHourly?: number; + keepLast?: number; + keepMonthly?: number; + keepWeekly?: number; + keepWithinDuration?: string; + keepYearly?: number; + } | null; + shortId: string; + updatedAt: number; + volumeId: number; + }; }; export type UpdateBackupScheduleResponse = UpdateBackupScheduleResponses[keyof UpdateBackupScheduleResponses]; export type GetBackupScheduleForVolumeData = { - body?: never; - path: { - volumeShortId: string; - }; - query?: never; - url: "/api/v1/backups/volume/{volumeShortId}"; + body?: never; + path: { + volumeShortId: string; + }; + query?: never; + url: '/api/v1/backups/volume/{volumeShortId}'; }; export type GetBackupScheduleForVolumeResponses = { - /** - * Backup schedule details for the volume - */ - 200: { - createdAt: number; - cronExpression: string; - enabled: boolean; - excludeIfPresent: Array | null; - excludePatterns: Array | null; - id: number; - includePatterns: Array | null; - lastBackupAt: number | null; - lastBackupError: string | null; - lastBackupStatus: "error" | "in_progress" | "success" | "warning" | null; - name: string; - nextBackupAt: number | null; - oneFileSystem: boolean; - repository: { - compressionMode: "auto" | "max" | "off" | null; - config: - | { - accessKeyId: string; - backend: "r2"; - bucket: string; - endpoint: string; - secretAccessKey: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - accessKeyId: string; - backend: "s3"; - bucket: string; - endpoint: string; - secretAccessKey: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - accountKey: string; - accountName: string; - backend: "azure"; - container: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - endpointSuffix?: string; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "gcs"; - bucket: string; - credentialsJson: string; - projectId: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "local"; - path: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "rclone"; - path: string; - remote: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "rest"; - url: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - password?: string; - path?: string; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - username?: string; - } - | { - backend: "sftp"; - host: string; - path: string; - privateKey: string; - user: string; - port?: number; - skipHostKeyCheck?: boolean; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - knownHosts?: string; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - }; - createdAt: number; - doctorResult: { - completedAt: number; - steps: Array<{ - error: string | null; - output: string | null; - step: string; - success: boolean; - }>; - success: boolean; - } | null; - id: string; - lastChecked: number | null; - lastError: string | null; - name: string; - shortId: string; - status: "cancelled" | "doctor" | "error" | "healthy" | "unknown" | null; - type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp"; - updatedAt: number; - }; - repositoryId: string; - retentionPolicy: { - keepDaily?: number; - keepHourly?: number; - keepLast?: number; - keepMonthly?: number; - keepWeekly?: number; - keepWithinDuration?: string; - keepYearly?: number; - } | null; - shortId: string; - updatedAt: number; - volume: { - autoRemount: boolean; - config: - | { - backend: "directory"; - path: string; - readOnly?: false; - } - | { - backend: "nfs"; - exportPath: string; - server: string; - version: "3" | "4" | "4.1"; - port?: number; - readOnly?: boolean; - } - | { - backend: "rclone"; - path: string; - remote: string; - readOnly?: boolean; - } - | { - backend: "sftp"; - host: string; - path: string; - username: string; - port?: number; - skipHostKeyCheck?: boolean; - knownHosts?: string; - password?: string; - privateKey?: string; - readOnly?: boolean; - } - | { - backend: "smb"; - server: string; - share: string; - vers?: "1.0" | "2.0" | "2.1" | "3.0" | "auto"; - port?: number; - domain?: string; - guest?: boolean; - password?: string; - readOnly?: boolean; - username?: string; - } - | { - backend: "webdav"; - path: string; - server: string; - port?: number; - password?: string; - readOnly?: boolean; - ssl?: boolean; - username?: string; - }; - createdAt: number; - id: number; - lastError: string | null; - lastHealthCheck: number; - name: string; - shortId: string; - status: "error" | "mounted" | "unmounted"; - type: "directory" | "nfs" | "rclone" | "sftp" | "smb" | "webdav"; - updatedAt: number; - }; - volumeId: number; - } | null; + /** + * Backup schedule details for the volume + */ + 200: { + createdAt: number; + cronExpression: string; + enabled: boolean; + excludeIfPresent: Array | null; + excludePatterns: Array | null; + id: number; + includePatterns: Array | null; + lastBackupAt: number | null; + lastBackupError: string | null; + lastBackupStatus: 'error' | 'in_progress' | 'success' | 'warning' | null; + name: string; + nextBackupAt: number | null; + oneFileSystem: boolean; + repository: { + compressionMode: 'auto' | 'max' | 'off' | null; + config: { + accessKeyId: string; + backend: 'r2'; + bucket: string; + endpoint: string; + secretAccessKey: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + accessKeyId: string; + backend: 's3'; + bucket: string; + endpoint: string; + secretAccessKey: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + accountKey: string; + accountName: string; + backend: 'azure'; + container: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + endpointSuffix?: string; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'gcs'; + bucket: string; + credentialsJson: string; + projectId: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'local'; + path: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'rclone'; + path: string; + remote: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'rest'; + url: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + password?: string; + path?: string; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + username?: string; + } | { + backend: 'sftp'; + host: string; + path: string; + privateKey: string; + user: string; + port?: number; + skipHostKeyCheck?: boolean; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + knownHosts?: string; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + }; + createdAt: number; + doctorResult: { + completedAt: number; + steps: Array<{ + error: string | null; + output: string | null; + step: string; + success: boolean; + }>; + success: boolean; + } | null; + id: string; + lastChecked: number | null; + lastError: string | null; + name: string; + shortId: string; + status: 'cancelled' | 'doctor' | 'error' | 'healthy' | 'unknown' | null; + type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3' | 'sftp'; + updatedAt: number; + }; + repositoryId: string; + retentionPolicy: { + keepDaily?: number; + keepHourly?: number; + keepLast?: number; + keepMonthly?: number; + keepWeekly?: number; + keepWithinDuration?: string; + keepYearly?: number; + } | null; + shortId: string; + updatedAt: number; + volume: { + autoRemount: boolean; + config: { + backend: 'directory'; + path: string; + readOnly?: false; + } | { + backend: 'nfs'; + exportPath: string; + server: string; + version: '3' | '4' | '4.1'; + port?: number; + readOnly?: boolean; + } | { + backend: 'rclone'; + path: string; + remote: string; + readOnly?: boolean; + } | { + backend: 'sftp'; + host: string; + path: string; + username: string; + port?: number; + skipHostKeyCheck?: boolean; + knownHosts?: string; + password?: string; + privateKey?: string; + readOnly?: boolean; + } | { + backend: 'smb'; + server: string; + share: string; + vers?: '1.0' | '2.0' | '2.1' | '3.0' | 'auto'; + port?: number; + domain?: string; + guest?: boolean; + password?: string; + readOnly?: boolean; + username?: string; + } | { + backend: 'webdav'; + path: string; + server: string; + port?: number; + password?: string; + readOnly?: boolean; + ssl?: boolean; + username?: string; + }; + createdAt: number; + id: number; + lastError: string | null; + lastHealthCheck: number; + name: string; + shortId: string; + status: 'error' | 'mounted' | 'unmounted'; + type: 'directory' | 'nfs' | 'rclone' | 'sftp' | 'smb' | 'webdav'; + updatedAt: number; + }; + volumeId: number; + } | null; }; -export type GetBackupScheduleForVolumeResponse = - GetBackupScheduleForVolumeResponses[keyof GetBackupScheduleForVolumeResponses]; +export type GetBackupScheduleForVolumeResponse = GetBackupScheduleForVolumeResponses[keyof GetBackupScheduleForVolumeResponses]; export type RunBackupNowData = { - body?: never; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/backups/{shortId}/run"; + body?: never; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/backups/{shortId}/run'; }; export type RunBackupNowResponses = { - /** - * Backup started successfully - */ - 200: { - success: boolean; - }; + /** + * Backup started successfully + */ + 200: { + success: boolean; + }; }; export type RunBackupNowResponse = RunBackupNowResponses[keyof RunBackupNowResponses]; export type StopBackupData = { - body?: never; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/backups/{shortId}/stop"; + body?: never; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/backups/{shortId}/stop'; }; export type StopBackupErrors = { - /** - * No backup is currently running for this schedule - */ - 409: unknown; + /** + * No backup is currently running for this schedule + */ + 409: unknown; }; export type StopBackupResponses = { - /** - * Backup stopped successfully - */ - 200: { - success: boolean; - }; + /** + * Backup stopped successfully + */ + 200: { + success: boolean; + }; }; export type StopBackupResponse = StopBackupResponses[keyof StopBackupResponses]; export type RunForgetData = { - body?: never; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/backups/{shortId}/forget"; + body?: never; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/backups/{shortId}/forget'; }; export type RunForgetResponses = { - /** - * Retention policy applied successfully - */ - 200: { - success: boolean; - }; + /** + * Retention policy applied successfully + */ + 200: { + success: boolean; + }; }; export type RunForgetResponse = RunForgetResponses[keyof RunForgetResponses]; export type GetScheduleNotificationsData = { - body?: never; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/backups/{shortId}/notifications"; + body?: never; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/backups/{shortId}/notifications'; }; export type GetScheduleNotificationsResponses = { - /** - * List of notification assignments for the schedule - */ - 200: Array<{ - createdAt: number; - destination: { - config: - | { - apiToken: string; - priority: -1 | 0 | 1; - type: "pushover"; - userKey: string; - devices?: string; - } - | { - botToken: string; - chatId: string; - type: "telegram"; - threadId?: string; - } - | { - from: string; - smtpHost: string; - smtpPort: number; - to: Array; - type: "email"; - useTLS: boolean; - fromName?: string; - password?: string; - username?: string; - } - | { - method: "GET" | "POST"; - type: "generic"; - url: string; - contentType?: string; - headers?: Array; - messageKey?: string; - titleKey?: string; - useJson?: boolean; - } - | { - priority: "default" | "high" | "low" | "max" | "min"; - topic: string; - type: "ntfy"; - accessToken?: string; - password?: string; - serverUrl?: string; - username?: string; - } - | { - priority: number; - serverUrl: string; - token: string; - type: "gotify"; - path?: string; - } - | { - shoutrrrUrl: string; - type: "custom"; - } - | { - type: "discord"; - webhookUrl: string; - avatarUrl?: string; - threadId?: string; - username?: string; - } - | { - type: "slack"; - webhookUrl: string; - channel?: string; - iconEmoji?: string; - username?: string; - }; - createdAt: number; - enabled: boolean; - id: number; - name: string; - type: "custom" | "discord" | "email" | "generic" | "gotify" | "ntfy" | "pushover" | "slack" | "telegram"; - updatedAt: number; - }; - destinationId: number; - notifyOnFailure: boolean; - notifyOnStart: boolean; - notifyOnSuccess: boolean; - notifyOnWarning: boolean; - scheduleId: number; - }>; + /** + * List of notification assignments for the schedule + */ + 200: Array<{ + createdAt: number; + destination: { + config: { + apiToken: string; + priority: -1 | 0 | 1; + type: 'pushover'; + userKey: string; + devices?: string; + } | { + botToken: string; + chatId: string; + type: 'telegram'; + threadId?: string; + } | { + from: string; + smtpHost: string; + smtpPort: number; + to: Array; + type: 'email'; + useTLS: boolean; + fromName?: string; + password?: string; + username?: string; + } | { + method: 'GET' | 'POST'; + type: 'generic'; + url: string; + contentType?: string; + headers?: Array; + messageKey?: string; + titleKey?: string; + useJson?: boolean; + } | { + priority: 'default' | 'high' | 'low' | 'max' | 'min'; + topic: string; + type: 'ntfy'; + accessToken?: string; + password?: string; + serverUrl?: string; + username?: string; + } | { + priority: number; + serverUrl: string; + token: string; + type: 'gotify'; + path?: string; + } | { + shoutrrrUrl: string; + type: 'custom'; + } | { + type: 'discord'; + webhookUrl: string; + avatarUrl?: string; + threadId?: string; + username?: string; + } | { + type: 'slack'; + webhookUrl: string; + channel?: string; + iconEmoji?: string; + username?: string; + }; + createdAt: number; + enabled: boolean; + id: number; + name: string; + type: 'custom' | 'discord' | 'email' | 'generic' | 'gotify' | 'ntfy' | 'pushover' | 'slack' | 'telegram'; + updatedAt: number; + }; + destinationId: number; + notifyOnFailure: boolean; + notifyOnStart: boolean; + notifyOnSuccess: boolean; + notifyOnWarning: boolean; + scheduleId: number; + }>; }; -export type GetScheduleNotificationsResponse = - GetScheduleNotificationsResponses[keyof GetScheduleNotificationsResponses]; +export type GetScheduleNotificationsResponse = GetScheduleNotificationsResponses[keyof GetScheduleNotificationsResponses]; export type UpdateScheduleNotificationsData = { - body?: { - assignments: Array<{ - destinationId: number; - notifyOnFailure: boolean; - notifyOnStart: boolean; - notifyOnSuccess: boolean; - notifyOnWarning: boolean; - }>; - }; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/backups/{shortId}/notifications"; + body?: { + assignments: Array<{ + destinationId: number; + notifyOnFailure: boolean; + notifyOnStart: boolean; + notifyOnSuccess: boolean; + notifyOnWarning: boolean; + }>; + }; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/backups/{shortId}/notifications'; }; export type UpdateScheduleNotificationsResponses = { - /** - * Notification assignments updated successfully - */ - 200: Array<{ - createdAt: number; - destination: { - config: - | { - apiToken: string; - priority: -1 | 0 | 1; - type: "pushover"; - userKey: string; - devices?: string; - } - | { - botToken: string; - chatId: string; - type: "telegram"; - threadId?: string; - } - | { - from: string; - smtpHost: string; - smtpPort: number; - to: Array; - type: "email"; - useTLS: boolean; - fromName?: string; - password?: string; - username?: string; - } - | { - method: "GET" | "POST"; - type: "generic"; - url: string; - contentType?: string; - headers?: Array; - messageKey?: string; - titleKey?: string; - useJson?: boolean; - } - | { - priority: "default" | "high" | "low" | "max" | "min"; - topic: string; - type: "ntfy"; - accessToken?: string; - password?: string; - serverUrl?: string; - username?: string; - } - | { - priority: number; - serverUrl: string; - token: string; - type: "gotify"; - path?: string; - } - | { - shoutrrrUrl: string; - type: "custom"; - } - | { - type: "discord"; - webhookUrl: string; - avatarUrl?: string; - threadId?: string; - username?: string; - } - | { - type: "slack"; - webhookUrl: string; - channel?: string; - iconEmoji?: string; - username?: string; - }; - createdAt: number; - enabled: boolean; - id: number; - name: string; - type: "custom" | "discord" | "email" | "generic" | "gotify" | "ntfy" | "pushover" | "slack" | "telegram"; - updatedAt: number; - }; - destinationId: number; - notifyOnFailure: boolean; - notifyOnStart: boolean; - notifyOnSuccess: boolean; - notifyOnWarning: boolean; - scheduleId: number; - }>; + /** + * Notification assignments updated successfully + */ + 200: Array<{ + createdAt: number; + destination: { + config: { + apiToken: string; + priority: -1 | 0 | 1; + type: 'pushover'; + userKey: string; + devices?: string; + } | { + botToken: string; + chatId: string; + type: 'telegram'; + threadId?: string; + } | { + from: string; + smtpHost: string; + smtpPort: number; + to: Array; + type: 'email'; + useTLS: boolean; + fromName?: string; + password?: string; + username?: string; + } | { + method: 'GET' | 'POST'; + type: 'generic'; + url: string; + contentType?: string; + headers?: Array; + messageKey?: string; + titleKey?: string; + useJson?: boolean; + } | { + priority: 'default' | 'high' | 'low' | 'max' | 'min'; + topic: string; + type: 'ntfy'; + accessToken?: string; + password?: string; + serverUrl?: string; + username?: string; + } | { + priority: number; + serverUrl: string; + token: string; + type: 'gotify'; + path?: string; + } | { + shoutrrrUrl: string; + type: 'custom'; + } | { + type: 'discord'; + webhookUrl: string; + avatarUrl?: string; + threadId?: string; + username?: string; + } | { + type: 'slack'; + webhookUrl: string; + channel?: string; + iconEmoji?: string; + username?: string; + }; + createdAt: number; + enabled: boolean; + id: number; + name: string; + type: 'custom' | 'discord' | 'email' | 'generic' | 'gotify' | 'ntfy' | 'pushover' | 'slack' | 'telegram'; + updatedAt: number; + }; + destinationId: number; + notifyOnFailure: boolean; + notifyOnStart: boolean; + notifyOnSuccess: boolean; + notifyOnWarning: boolean; + scheduleId: number; + }>; }; -export type UpdateScheduleNotificationsResponse = - UpdateScheduleNotificationsResponses[keyof UpdateScheduleNotificationsResponses]; +export type UpdateScheduleNotificationsResponse = UpdateScheduleNotificationsResponses[keyof UpdateScheduleNotificationsResponses]; export type GetScheduleMirrorsData = { - body?: never; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/backups/{shortId}/mirrors"; + body?: never; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/backups/{shortId}/mirrors'; }; export type GetScheduleMirrorsResponses = { - /** - * List of mirror repository assignments for the schedule - */ - 200: Array<{ - createdAt: number; - enabled: boolean; - lastCopyAt: number | null; - lastCopyError: string | null; - lastCopyStatus: "error" | "in_progress" | "success" | null; - repository: { - compressionMode: "auto" | "max" | "off" | null; - config: - | { - accessKeyId: string; - backend: "r2"; - bucket: string; - endpoint: string; - secretAccessKey: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - accessKeyId: string; - backend: "s3"; - bucket: string; - endpoint: string; - secretAccessKey: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - accountKey: string; - accountName: string; - backend: "azure"; - container: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - endpointSuffix?: string; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "gcs"; - bucket: string; - credentialsJson: string; - projectId: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "local"; - path: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "rclone"; - path: string; - remote: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "rest"; - url: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - password?: string; - path?: string; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - username?: string; - } - | { - backend: "sftp"; - host: string; - path: string; - privateKey: string; - user: string; - port?: number; - skipHostKeyCheck?: boolean; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - knownHosts?: string; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - }; - createdAt: number; - doctorResult: { - completedAt: number; - steps: Array<{ - error: string | null; - output: string | null; - step: string; - success: boolean; - }>; - success: boolean; - } | null; - id: string; - lastChecked: number | null; - lastError: string | null; - name: string; - shortId: string; - status: "cancelled" | "doctor" | "error" | "healthy" | "unknown" | null; - type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp"; - updatedAt: number; - }; - repositoryId: string; - scheduleId: string; - }>; + /** + * List of mirror repository assignments for the schedule + */ + 200: Array<{ + createdAt: number; + enabled: boolean; + lastCopyAt: number | null; + lastCopyError: string | null; + lastCopyStatus: 'error' | 'in_progress' | 'success' | null; + repository: { + compressionMode: 'auto' | 'max' | 'off' | null; + config: { + accessKeyId: string; + backend: 'r2'; + bucket: string; + endpoint: string; + secretAccessKey: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + accessKeyId: string; + backend: 's3'; + bucket: string; + endpoint: string; + secretAccessKey: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + accountKey: string; + accountName: string; + backend: 'azure'; + container: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + endpointSuffix?: string; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'gcs'; + bucket: string; + credentialsJson: string; + projectId: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'local'; + path: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'rclone'; + path: string; + remote: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'rest'; + url: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + password?: string; + path?: string; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + username?: string; + } | { + backend: 'sftp'; + host: string; + path: string; + privateKey: string; + user: string; + port?: number; + skipHostKeyCheck?: boolean; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + knownHosts?: string; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + }; + createdAt: number; + doctorResult: { + completedAt: number; + steps: Array<{ + error: string | null; + output: string | null; + step: string; + success: boolean; + }>; + success: boolean; + } | null; + id: string; + lastChecked: number | null; + lastError: string | null; + name: string; + shortId: string; + status: 'cancelled' | 'doctor' | 'error' | 'healthy' | 'unknown' | null; + type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3' | 'sftp'; + updatedAt: number; + }; + repositoryId: string; + scheduleId: string; + }>; }; export type GetScheduleMirrorsResponse = GetScheduleMirrorsResponses[keyof GetScheduleMirrorsResponses]; export type UpdateScheduleMirrorsData = { - body?: { - mirrors: Array<{ - enabled: boolean; - repositoryId: string; - }>; - }; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/backups/{shortId}/mirrors"; + body?: { + mirrors: Array<{ + enabled: boolean; + repositoryId: string; + }>; + }; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/backups/{shortId}/mirrors'; }; export type UpdateScheduleMirrorsResponses = { - /** - * Mirror assignments updated successfully - */ - 200: Array<{ - createdAt: number; - enabled: boolean; - lastCopyAt: number | null; - lastCopyError: string | null; - lastCopyStatus: "error" | "in_progress" | "success" | null; - repository: { - compressionMode: "auto" | "max" | "off" | null; - config: - | { - accessKeyId: string; - backend: "r2"; - bucket: string; - endpoint: string; - secretAccessKey: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - accessKeyId: string; - backend: "s3"; - bucket: string; - endpoint: string; - secretAccessKey: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - accountKey: string; - accountName: string; - backend: "azure"; - container: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - endpointSuffix?: string; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "gcs"; - bucket: string; - credentialsJson: string; - projectId: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "local"; - path: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "rclone"; - path: string; - remote: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - } - | { - backend: "rest"; - url: string; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - password?: string; - path?: string; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - username?: string; - } - | { - backend: "sftp"; - host: string; - path: string; - privateKey: string; - user: string; - port?: number; - skipHostKeyCheck?: boolean; - cacert?: string; - customPassword?: string; - downloadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - insecureTls?: boolean; - isExistingRepository?: boolean; - knownHosts?: string; - uploadLimit?: { - unit?: "Gbps" | "Kbps" | "Mbps"; - value?: number; - enabled?: boolean; - }; - }; - createdAt: number; - doctorResult: { - completedAt: number; - steps: Array<{ - error: string | null; - output: string | null; - step: string; - success: boolean; - }>; - success: boolean; - } | null; - id: string; - lastChecked: number | null; - lastError: string | null; - name: string; - shortId: string; - status: "cancelled" | "doctor" | "error" | "healthy" | "unknown" | null; - type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp"; - updatedAt: number; - }; - repositoryId: string; - scheduleId: string; - }>; + /** + * Mirror assignments updated successfully + */ + 200: Array<{ + createdAt: number; + enabled: boolean; + lastCopyAt: number | null; + lastCopyError: string | null; + lastCopyStatus: 'error' | 'in_progress' | 'success' | null; + repository: { + compressionMode: 'auto' | 'max' | 'off' | null; + config: { + accessKeyId: string; + backend: 'r2'; + bucket: string; + endpoint: string; + secretAccessKey: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + accessKeyId: string; + backend: 's3'; + bucket: string; + endpoint: string; + secretAccessKey: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + accountKey: string; + accountName: string; + backend: 'azure'; + container: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + endpointSuffix?: string; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'gcs'; + bucket: string; + credentialsJson: string; + projectId: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'local'; + path: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'rclone'; + path: string; + remote: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + } | { + backend: 'rest'; + url: string; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + password?: string; + path?: string; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + username?: string; + } | { + backend: 'sftp'; + host: string; + path: string; + privateKey: string; + user: string; + port?: number; + skipHostKeyCheck?: boolean; + cacert?: string; + customPassword?: string; + downloadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + insecureTls?: boolean; + isExistingRepository?: boolean; + knownHosts?: string; + uploadLimit?: { + unit?: 'Gbps' | 'Kbps' | 'Mbps'; + value?: number; + enabled?: boolean; + }; + }; + createdAt: number; + doctorResult: { + completedAt: number; + steps: Array<{ + error: string | null; + output: string | null; + step: string; + success: boolean; + }>; + success: boolean; + } | null; + id: string; + lastChecked: number | null; + lastError: string | null; + name: string; + shortId: string; + status: 'cancelled' | 'doctor' | 'error' | 'healthy' | 'unknown' | null; + type: 'azure' | 'gcs' | 'local' | 'r2' | 'rclone' | 'rest' | 's3' | 'sftp'; + updatedAt: number; + }; + repositoryId: string; + scheduleId: string; + }>; }; export type UpdateScheduleMirrorsResponse = UpdateScheduleMirrorsResponses[keyof UpdateScheduleMirrorsResponses]; export type GetMirrorCompatibilityData = { - body?: never; - path: { - shortId: string; - }; - query?: never; - url: "/api/v1/backups/{shortId}/mirrors/compatibility"; + body?: never; + path: { + shortId: string; + }; + query?: never; + url: '/api/v1/backups/{shortId}/mirrors/compatibility'; }; export type GetMirrorCompatibilityResponses = { - /** - * List of repositories with their mirror compatibility status - */ - 200: Array<{ - compatible: boolean; - reason: string | null; - repositoryId: string; - }>; + /** + * List of repositories with their mirror compatibility status + */ + 200: Array<{ + compatible: boolean; + reason: string | null; + repositoryId: string; + }>; }; export type GetMirrorCompatibilityResponse = GetMirrorCompatibilityResponses[keyof GetMirrorCompatibilityResponses]; export type ReorderBackupSchedulesData = { - body?: { - scheduleShortIds: Array; - }; - path?: never; - query?: never; - url: "/api/v1/backups/reorder"; + body?: { + scheduleShortIds: Array; + }; + path?: never; + query?: never; + url: '/api/v1/backups/reorder'; }; export type ReorderBackupSchedulesResponses = { - /** - * Backup schedules reordered successfully - */ - 200: { - success: boolean; - }; + /** + * Backup schedules reordered successfully + */ + 200: { + success: boolean; + }; }; export type ReorderBackupSchedulesResponse = ReorderBackupSchedulesResponses[keyof ReorderBackupSchedulesResponses]; export type ListNotificationDestinationsData = { - body?: never; - path?: never; - query?: never; - url: "/api/v1/notifications/destinations"; + body?: never; + path?: never; + query?: never; + url: '/api/v1/notifications/destinations'; }; export type ListNotificationDestinationsResponses = { - /** - * A list of notification destinations - */ - 200: Array<{ - config: - | { - apiToken: string; - priority: -1 | 0 | 1; - type: "pushover"; - userKey: string; - devices?: string; - } - | { - botToken: string; - chatId: string; - type: "telegram"; - threadId?: string; - } - | { - from: string; - smtpHost: string; - smtpPort: number; - to: Array; - type: "email"; - useTLS: boolean; - fromName?: string; - password?: string; - username?: string; - } - | { - method: "GET" | "POST"; - type: "generic"; - url: string; - contentType?: string; - headers?: Array; - messageKey?: string; - titleKey?: string; - useJson?: boolean; - } - | { - priority: "default" | "high" | "low" | "max" | "min"; - topic: string; - type: "ntfy"; - accessToken?: string; - password?: string; - serverUrl?: string; - username?: string; - } - | { - priority: number; - serverUrl: string; - token: string; - type: "gotify"; - path?: string; - } - | { - shoutrrrUrl: string; - type: "custom"; - } - | { - type: "discord"; - webhookUrl: string; - avatarUrl?: string; - threadId?: string; - username?: string; - } - | { - type: "slack"; - webhookUrl: string; - channel?: string; - iconEmoji?: string; - username?: string; - }; - createdAt: number; - enabled: boolean; - id: number; - name: string; - type: "custom" | "discord" | "email" | "generic" | "gotify" | "ntfy" | "pushover" | "slack" | "telegram"; - updatedAt: number; - }>; + /** + * A list of notification destinations + */ + 200: Array<{ + config: { + apiToken: string; + priority: -1 | 0 | 1; + type: 'pushover'; + userKey: string; + devices?: string; + } | { + botToken: string; + chatId: string; + type: 'telegram'; + threadId?: string; + } | { + from: string; + smtpHost: string; + smtpPort: number; + to: Array; + type: 'email'; + useTLS: boolean; + fromName?: string; + password?: string; + username?: string; + } | { + method: 'GET' | 'POST'; + type: 'generic'; + url: string; + contentType?: string; + headers?: Array; + messageKey?: string; + titleKey?: string; + useJson?: boolean; + } | { + priority: 'default' | 'high' | 'low' | 'max' | 'min'; + topic: string; + type: 'ntfy'; + accessToken?: string; + password?: string; + serverUrl?: string; + username?: string; + } | { + priority: number; + serverUrl: string; + token: string; + type: 'gotify'; + path?: string; + } | { + shoutrrrUrl: string; + type: 'custom'; + } | { + type: 'discord'; + webhookUrl: string; + avatarUrl?: string; + threadId?: string; + username?: string; + } | { + type: 'slack'; + webhookUrl: string; + channel?: string; + iconEmoji?: string; + username?: string; + }; + createdAt: number; + enabled: boolean; + id: number; + name: string; + type: 'custom' | 'discord' | 'email' | 'generic' | 'gotify' | 'ntfy' | 'pushover' | 'slack' | 'telegram'; + updatedAt: number; + }>; }; -export type ListNotificationDestinationsResponse = - ListNotificationDestinationsResponses[keyof ListNotificationDestinationsResponses]; +export type ListNotificationDestinationsResponse = ListNotificationDestinationsResponses[keyof ListNotificationDestinationsResponses]; export type CreateNotificationDestinationData = { - body?: { - config: - | { - apiToken: string; - priority: -1 | 0 | 1; - type: "pushover"; - userKey: string; - devices?: string; - } - | { - botToken: string; - chatId: string; - type: "telegram"; - threadId?: string; - } - | { - from: string; - smtpHost: string; - smtpPort: number; - to: Array; - type: "email"; - useTLS: boolean; - fromName?: string; - password?: string; - username?: string; - } - | { - method: "GET" | "POST"; - type: "generic"; - url: string; - contentType?: string; - headers?: Array; - messageKey?: string; - titleKey?: string; - useJson?: boolean; - } - | { - priority: "default" | "high" | "low" | "max" | "min"; - topic: string; - type: "ntfy"; - accessToken?: string; - password?: string; - serverUrl?: string; - username?: string; - } - | { - priority: number; - serverUrl: string; - token: string; - type: "gotify"; - path?: string; - } - | { - shoutrrrUrl: string; - type: "custom"; - } - | { - type: "discord"; - webhookUrl: string; - avatarUrl?: string; - threadId?: string; - username?: string; - } - | { - type: "slack"; - webhookUrl: string; - channel?: string; - iconEmoji?: string; - username?: string; - }; - name: string; - }; - path?: never; - query?: never; - url: "/api/v1/notifications/destinations"; + body?: { + config: { + apiToken: string; + priority: -1 | 0 | 1; + type: 'pushover'; + userKey: string; + devices?: string; + } | { + botToken: string; + chatId: string; + type: 'telegram'; + threadId?: string; + } | { + from: string; + smtpHost: string; + smtpPort: number; + to: Array; + type: 'email'; + useTLS: boolean; + fromName?: string; + password?: string; + username?: string; + } | { + method: 'GET' | 'POST'; + type: 'generic'; + url: string; + contentType?: string; + headers?: Array; + messageKey?: string; + titleKey?: string; + useJson?: boolean; + } | { + priority: 'default' | 'high' | 'low' | 'max' | 'min'; + topic: string; + type: 'ntfy'; + accessToken?: string; + password?: string; + serverUrl?: string; + username?: string; + } | { + priority: number; + serverUrl: string; + token: string; + type: 'gotify'; + path?: string; + } | { + shoutrrrUrl: string; + type: 'custom'; + } | { + type: 'discord'; + webhookUrl: string; + avatarUrl?: string; + threadId?: string; + username?: string; + } | { + type: 'slack'; + webhookUrl: string; + channel?: string; + iconEmoji?: string; + username?: string; + }; + name: string; + }; + path?: never; + query?: never; + url: '/api/v1/notifications/destinations'; }; export type CreateNotificationDestinationResponses = { - /** - * Notification destination created successfully - */ - 201: { - config: - | { - apiToken: string; - priority: -1 | 0 | 1; - type: "pushover"; - userKey: string; - devices?: string; - } - | { - botToken: string; - chatId: string; - type: "telegram"; - threadId?: string; - } - | { - from: string; - smtpHost: string; - smtpPort: number; - to: Array; - type: "email"; - useTLS: boolean; - fromName?: string; - password?: string; - username?: string; - } - | { - method: "GET" | "POST"; - type: "generic"; - url: string; - contentType?: string; - headers?: Array; - messageKey?: string; - titleKey?: string; - useJson?: boolean; - } - | { - priority: "default" | "high" | "low" | "max" | "min"; - topic: string; - type: "ntfy"; - accessToken?: string; - password?: string; - serverUrl?: string; - username?: string; - } - | { - priority: number; - serverUrl: string; - token: string; - type: "gotify"; - path?: string; - } - | { - shoutrrrUrl: string; - type: "custom"; - } - | { - type: "discord"; - webhookUrl: string; - avatarUrl?: string; - threadId?: string; - username?: string; - } - | { - type: "slack"; - webhookUrl: string; - channel?: string; - iconEmoji?: string; - username?: string; - }; - createdAt: number; - enabled: boolean; - id: number; - name: string; - type: "custom" | "discord" | "email" | "generic" | "gotify" | "ntfy" | "pushover" | "slack" | "telegram"; - updatedAt: number; - }; + /** + * Notification destination created successfully + */ + 201: { + config: { + apiToken: string; + priority: -1 | 0 | 1; + type: 'pushover'; + userKey: string; + devices?: string; + } | { + botToken: string; + chatId: string; + type: 'telegram'; + threadId?: string; + } | { + from: string; + smtpHost: string; + smtpPort: number; + to: Array; + type: 'email'; + useTLS: boolean; + fromName?: string; + password?: string; + username?: string; + } | { + method: 'GET' | 'POST'; + type: 'generic'; + url: string; + contentType?: string; + headers?: Array; + messageKey?: string; + titleKey?: string; + useJson?: boolean; + } | { + priority: 'default' | 'high' | 'low' | 'max' | 'min'; + topic: string; + type: 'ntfy'; + accessToken?: string; + password?: string; + serverUrl?: string; + username?: string; + } | { + priority: number; + serverUrl: string; + token: string; + type: 'gotify'; + path?: string; + } | { + shoutrrrUrl: string; + type: 'custom'; + } | { + type: 'discord'; + webhookUrl: string; + avatarUrl?: string; + threadId?: string; + username?: string; + } | { + type: 'slack'; + webhookUrl: string; + channel?: string; + iconEmoji?: string; + username?: string; + }; + createdAt: number; + enabled: boolean; + id: number; + name: string; + type: 'custom' | 'discord' | 'email' | 'generic' | 'gotify' | 'ntfy' | 'pushover' | 'slack' | 'telegram'; + updatedAt: number; + }; }; -export type CreateNotificationDestinationResponse = - CreateNotificationDestinationResponses[keyof CreateNotificationDestinationResponses]; +export type CreateNotificationDestinationResponse = CreateNotificationDestinationResponses[keyof CreateNotificationDestinationResponses]; export type DeleteNotificationDestinationData = { - body?: never; - path: { - id: string; - }; - query?: never; - url: "/api/v1/notifications/destinations/{id}"; + body?: never; + path: { + id: string; + }; + query?: never; + url: '/api/v1/notifications/destinations/{id}'; }; export type DeleteNotificationDestinationErrors = { - /** - * Notification destination not found - */ - 404: unknown; + /** + * Notification destination not found + */ + 404: unknown; }; export type DeleteNotificationDestinationResponses = { - /** - * Notification destination deleted successfully - */ - 200: { - message: string; - }; + /** + * Notification destination deleted successfully + */ + 200: { + message: string; + }; }; -export type DeleteNotificationDestinationResponse = - DeleteNotificationDestinationResponses[keyof DeleteNotificationDestinationResponses]; +export type DeleteNotificationDestinationResponse = DeleteNotificationDestinationResponses[keyof DeleteNotificationDestinationResponses]; export type GetNotificationDestinationData = { - body?: never; - path: { - id: string; - }; - query?: never; - url: "/api/v1/notifications/destinations/{id}"; + body?: never; + path: { + id: string; + }; + query?: never; + url: '/api/v1/notifications/destinations/{id}'; }; export type GetNotificationDestinationErrors = { - /** - * Notification destination not found - */ - 404: unknown; + /** + * Notification destination not found + */ + 404: unknown; }; export type GetNotificationDestinationResponses = { - /** - * Notification destination details - */ - 200: { - config: - | { - apiToken: string; - priority: -1 | 0 | 1; - type: "pushover"; - userKey: string; - devices?: string; - } - | { - botToken: string; - chatId: string; - type: "telegram"; - threadId?: string; - } - | { - from: string; - smtpHost: string; - smtpPort: number; - to: Array; - type: "email"; - useTLS: boolean; - fromName?: string; - password?: string; - username?: string; - } - | { - method: "GET" | "POST"; - type: "generic"; - url: string; - contentType?: string; - headers?: Array; - messageKey?: string; - titleKey?: string; - useJson?: boolean; - } - | { - priority: "default" | "high" | "low" | "max" | "min"; - topic: string; - type: "ntfy"; - accessToken?: string; - password?: string; - serverUrl?: string; - username?: string; - } - | { - priority: number; - serverUrl: string; - token: string; - type: "gotify"; - path?: string; - } - | { - shoutrrrUrl: string; - type: "custom"; - } - | { - type: "discord"; - webhookUrl: string; - avatarUrl?: string; - threadId?: string; - username?: string; - } - | { - type: "slack"; - webhookUrl: string; - channel?: string; - iconEmoji?: string; - username?: string; - }; - createdAt: number; - enabled: boolean; - id: number; - name: string; - type: "custom" | "discord" | "email" | "generic" | "gotify" | "ntfy" | "pushover" | "slack" | "telegram"; - updatedAt: number; - }; + /** + * Notification destination details + */ + 200: { + config: { + apiToken: string; + priority: -1 | 0 | 1; + type: 'pushover'; + userKey: string; + devices?: string; + } | { + botToken: string; + chatId: string; + type: 'telegram'; + threadId?: string; + } | { + from: string; + smtpHost: string; + smtpPort: number; + to: Array; + type: 'email'; + useTLS: boolean; + fromName?: string; + password?: string; + username?: string; + } | { + method: 'GET' | 'POST'; + type: 'generic'; + url: string; + contentType?: string; + headers?: Array; + messageKey?: string; + titleKey?: string; + useJson?: boolean; + } | { + priority: 'default' | 'high' | 'low' | 'max' | 'min'; + topic: string; + type: 'ntfy'; + accessToken?: string; + password?: string; + serverUrl?: string; + username?: string; + } | { + priority: number; + serverUrl: string; + token: string; + type: 'gotify'; + path?: string; + } | { + shoutrrrUrl: string; + type: 'custom'; + } | { + type: 'discord'; + webhookUrl: string; + avatarUrl?: string; + threadId?: string; + username?: string; + } | { + type: 'slack'; + webhookUrl: string; + channel?: string; + iconEmoji?: string; + username?: string; + }; + createdAt: number; + enabled: boolean; + id: number; + name: string; + type: 'custom' | 'discord' | 'email' | 'generic' | 'gotify' | 'ntfy' | 'pushover' | 'slack' | 'telegram'; + updatedAt: number; + }; }; -export type GetNotificationDestinationResponse = - GetNotificationDestinationResponses[keyof GetNotificationDestinationResponses]; +export type GetNotificationDestinationResponse = GetNotificationDestinationResponses[keyof GetNotificationDestinationResponses]; export type UpdateNotificationDestinationData = { - body?: { - config?: - | { - apiToken: string; - priority: -1 | 0 | 1; - type: "pushover"; - userKey: string; - devices?: string; - } - | { - botToken: string; - chatId: string; - type: "telegram"; - threadId?: string; - } - | { - from: string; - smtpHost: string; - smtpPort: number; - to: Array; - type: "email"; - useTLS: boolean; - fromName?: string; - password?: string; - username?: string; - } - | { - method: "GET" | "POST"; - type: "generic"; - url: string; - contentType?: string; - headers?: Array; - messageKey?: string; - titleKey?: string; - useJson?: boolean; - } - | { - priority: "default" | "high" | "low" | "max" | "min"; - topic: string; - type: "ntfy"; - accessToken?: string; - password?: string; - serverUrl?: string; - username?: string; - } - | { - priority: number; - serverUrl: string; - token: string; - type: "gotify"; - path?: string; - } - | { - shoutrrrUrl: string; - type: "custom"; - } - | { - type: "discord"; - webhookUrl: string; - avatarUrl?: string; - threadId?: string; - username?: string; - } - | { - type: "slack"; - webhookUrl: string; - channel?: string; - iconEmoji?: string; - username?: string; - }; - enabled?: boolean; - name?: string; - }; - path: { - id: string; - }; - query?: never; - url: "/api/v1/notifications/destinations/{id}"; + body?: { + config?: { + apiToken: string; + priority: -1 | 0 | 1; + type: 'pushover'; + userKey: string; + devices?: string; + } | { + botToken: string; + chatId: string; + type: 'telegram'; + threadId?: string; + } | { + from: string; + smtpHost: string; + smtpPort: number; + to: Array; + type: 'email'; + useTLS: boolean; + fromName?: string; + password?: string; + username?: string; + } | { + method: 'GET' | 'POST'; + type: 'generic'; + url: string; + contentType?: string; + headers?: Array; + messageKey?: string; + titleKey?: string; + useJson?: boolean; + } | { + priority: 'default' | 'high' | 'low' | 'max' | 'min'; + topic: string; + type: 'ntfy'; + accessToken?: string; + password?: string; + serverUrl?: string; + username?: string; + } | { + priority: number; + serverUrl: string; + token: string; + type: 'gotify'; + path?: string; + } | { + shoutrrrUrl: string; + type: 'custom'; + } | { + type: 'discord'; + webhookUrl: string; + avatarUrl?: string; + threadId?: string; + username?: string; + } | { + type: 'slack'; + webhookUrl: string; + channel?: string; + iconEmoji?: string; + username?: string; + }; + enabled?: boolean; + name?: string; + }; + path: { + id: string; + }; + query?: never; + url: '/api/v1/notifications/destinations/{id}'; }; export type UpdateNotificationDestinationErrors = { - /** - * Notification destination not found - */ - 404: unknown; + /** + * Notification destination not found + */ + 404: unknown; }; export type UpdateNotificationDestinationResponses = { - /** - * Notification destination updated successfully - */ - 200: { - config: - | { - apiToken: string; - priority: -1 | 0 | 1; - type: "pushover"; - userKey: string; - devices?: string; - } - | { - botToken: string; - chatId: string; - type: "telegram"; - threadId?: string; - } - | { - from: string; - smtpHost: string; - smtpPort: number; - to: Array; - type: "email"; - useTLS: boolean; - fromName?: string; - password?: string; - username?: string; - } - | { - method: "GET" | "POST"; - type: "generic"; - url: string; - contentType?: string; - headers?: Array; - messageKey?: string; - titleKey?: string; - useJson?: boolean; - } - | { - priority: "default" | "high" | "low" | "max" | "min"; - topic: string; - type: "ntfy"; - accessToken?: string; - password?: string; - serverUrl?: string; - username?: string; - } - | { - priority: number; - serverUrl: string; - token: string; - type: "gotify"; - path?: string; - } - | { - shoutrrrUrl: string; - type: "custom"; - } - | { - type: "discord"; - webhookUrl: string; - avatarUrl?: string; - threadId?: string; - username?: string; - } - | { - type: "slack"; - webhookUrl: string; - channel?: string; - iconEmoji?: string; - username?: string; - }; - createdAt: number; - enabled: boolean; - id: number; - name: string; - type: "custom" | "discord" | "email" | "generic" | "gotify" | "ntfy" | "pushover" | "slack" | "telegram"; - updatedAt: number; - }; + /** + * Notification destination updated successfully + */ + 200: { + config: { + apiToken: string; + priority: -1 | 0 | 1; + type: 'pushover'; + userKey: string; + devices?: string; + } | { + botToken: string; + chatId: string; + type: 'telegram'; + threadId?: string; + } | { + from: string; + smtpHost: string; + smtpPort: number; + to: Array; + type: 'email'; + useTLS: boolean; + fromName?: string; + password?: string; + username?: string; + } | { + method: 'GET' | 'POST'; + type: 'generic'; + url: string; + contentType?: string; + headers?: Array; + messageKey?: string; + titleKey?: string; + useJson?: boolean; + } | { + priority: 'default' | 'high' | 'low' | 'max' | 'min'; + topic: string; + type: 'ntfy'; + accessToken?: string; + password?: string; + serverUrl?: string; + username?: string; + } | { + priority: number; + serverUrl: string; + token: string; + type: 'gotify'; + path?: string; + } | { + shoutrrrUrl: string; + type: 'custom'; + } | { + type: 'discord'; + webhookUrl: string; + avatarUrl?: string; + threadId?: string; + username?: string; + } | { + type: 'slack'; + webhookUrl: string; + channel?: string; + iconEmoji?: string; + username?: string; + }; + createdAt: number; + enabled: boolean; + id: number; + name: string; + type: 'custom' | 'discord' | 'email' | 'generic' | 'gotify' | 'ntfy' | 'pushover' | 'slack' | 'telegram'; + updatedAt: number; + }; }; -export type UpdateNotificationDestinationResponse = - UpdateNotificationDestinationResponses[keyof UpdateNotificationDestinationResponses]; +export type UpdateNotificationDestinationResponse = UpdateNotificationDestinationResponses[keyof UpdateNotificationDestinationResponses]; export type TestNotificationDestinationData = { - body?: never; - path: { - id: string; - }; - query?: never; - url: "/api/v1/notifications/destinations/{id}/test"; + body?: never; + path: { + id: string; + }; + query?: never; + url: '/api/v1/notifications/destinations/{id}/test'; }; export type TestNotificationDestinationErrors = { - /** - * Notification destination not found - */ - 404: unknown; - /** - * Cannot test disabled destination - */ - 409: unknown; - /** - * Failed to send test notification - */ - 500: unknown; + /** + * Notification destination not found + */ + 404: unknown; + /** + * Cannot test disabled destination + */ + 409: unknown; + /** + * Failed to send test notification + */ + 500: unknown; }; export type TestNotificationDestinationResponses = { - /** - * Test notification sent successfully - */ - 200: { - success: boolean; - }; + /** + * Test notification sent successfully + */ + 200: { + success: boolean; + }; }; -export type TestNotificationDestinationResponse = - TestNotificationDestinationResponses[keyof TestNotificationDestinationResponses]; +export type TestNotificationDestinationResponse = TestNotificationDestinationResponses[keyof TestNotificationDestinationResponses]; export type GetSystemInfoData = { - body?: never; - path?: never; - query?: never; - url: "/api/v1/system/info"; + body?: never; + path?: never; + query?: never; + url: '/api/v1/system/info'; }; export type GetSystemInfoResponses = { - /** - * System information with enabled capabilities - */ - 200: { - capabilities: { - rclone: boolean; - sysAdmin: boolean; - }; - }; + /** + * System information with enabled capabilities + */ + 200: { + capabilities: { + rclone: boolean; + sysAdmin: boolean; + }; + }; }; export type GetSystemInfoResponse = GetSystemInfoResponses[keyof GetSystemInfoResponses]; export type GetUpdatesData = { - body?: never; - path?: never; - query?: never; - url: "/api/v1/system/updates"; + body?: never; + path?: never; + query?: never; + url: '/api/v1/system/updates'; }; export type GetUpdatesResponses = { - /** - * Update information and missed releases - */ - 200: { - currentVersion: string; - hasUpdate: boolean; - latestVersion: string; - missedReleases: Array<{ - body: string; - publishedAt: string; - url: string; - version: string; - }>; - }; + /** + * Update information and missed releases + */ + 200: { + currentVersion: string; + hasUpdate: boolean; + latestVersion: string; + missedReleases: Array<{ + body: string; + publishedAt: string; + url: string; + version: string; + }>; + }; }; export type GetUpdatesResponse = GetUpdatesResponses[keyof GetUpdatesResponses]; export type GetRegistrationStatusData = { - body?: never; - path?: never; - query?: never; - url: "/api/v1/system/registration-status"; + body?: never; + path?: never; + query?: never; + url: '/api/v1/system/registration-status'; }; export type GetRegistrationStatusResponses = { - /** - * Registration status - */ - 200: { - enabled: boolean; - }; + /** + * Registration status + */ + 200: { + enabled: boolean; + }; }; export type GetRegistrationStatusResponse = GetRegistrationStatusResponses[keyof GetRegistrationStatusResponses]; export type SetRegistrationStatusData = { - body?: { - enabled: boolean; - }; - path?: never; - query?: never; - url: "/api/v1/system/registration-status"; + body?: { + enabled: boolean; + }; + path?: never; + query?: never; + url: '/api/v1/system/registration-status'; }; export type SetRegistrationStatusResponses = { - /** - * Registration status updated - */ - 200: { - enabled: boolean; - }; + /** + * Registration status updated + */ + 200: { + enabled: boolean; + }; }; export type SetRegistrationStatusResponse = SetRegistrationStatusResponses[keyof SetRegistrationStatusResponses]; export type DownloadResticPasswordData = { - body?: { - password: string; - }; - path?: never; - query?: never; - url: "/api/v1/system/restic-password"; + body?: { + password: string; + }; + path?: never; + query?: never; + url: '/api/v1/system/restic-password'; }; export type DownloadResticPasswordResponses = { - /** - * Organization's Restic password - */ - 200: string; + /** + * Organization's Restic password + */ + 200: string; }; export type DownloadResticPasswordResponse = DownloadResticPasswordResponses[keyof DownloadResticPasswordResponses]; export type GetDevPanelData = { - body?: never; - path?: never; - query?: never; - url: "/api/v1/system/dev-panel"; + body?: never; + path?: never; + query?: never; + url: '/api/v1/system/dev-panel'; }; export type GetDevPanelResponses = { - /** - * Dev panel status - */ - 200: { - enabled: boolean; - }; + /** + * Dev panel status + */ + 200: { + enabled: boolean; + }; }; export type GetDevPanelResponse = GetDevPanelResponses[keyof GetDevPanelResponses]; diff --git a/app/client/components/app-sidebar.tsx b/app/client/components/app-sidebar.tsx index 317e5cea..8ed68aef 100644 --- a/app/client/components/app-sidebar.tsx +++ b/app/client/components/app-sidebar.tsx @@ -18,6 +18,7 @@ import { cn } from "~/client/lib/utils"; import { APP_VERSION, RCLONE_VERSION, RESTIC_VERSION, SHOUTRRR_VERSION } from "~/client/lib/version"; import { useUpdates } from "~/client/hooks/use-updates"; import { ReleaseNotesDialog } from "./release-notes-dialog"; +import { OrganizationSwitcher } from "./organization-switcher"; import { Link } from "@tanstack/react-router"; const items = [ @@ -104,7 +105,8 @@ export function AppSidebar() { - + +
diff --git a/app/client/components/layout.tsx b/app/client/components/layout.tsx index 8593e31d..ff8297bd 100644 --- a/app/client/components/layout.tsx +++ b/app/client/components/layout.tsx @@ -44,7 +44,7 @@ export function Layout({ loaderData }: Props) {
Welcome,  - {loaderData.user?.username} + {loaderData.user.name} + ))} +
+
+ )} + ); diff --git a/app/client/modules/settings/components/sso/sso-settings-section.tsx b/app/client/modules/settings/components/sso/sso-settings-section.tsx new file mode 100644 index 00000000..31186940 --- /dev/null +++ b/app/client/modules/settings/components/sso/sso-settings-section.tsx @@ -0,0 +1,549 @@ +import { arktypeResolver } from "@hookform/resolvers/arktype"; +import { useMutation, useSuspenseQuery } from "@tanstack/react-query"; +import { type } from "arktype"; +import { Ban, Trash2 } from "lucide-react"; +import { useState } from "react"; +import { useForm } from "react-hook-form"; +import { toast } from "sonner"; +import { + deleteSsoInvitationMutation, + deleteSsoProviderMutation, + getSsoSettingsOptions, +} from "~/client/api-client/@tanstack/react-query.gen"; +import { Alert, AlertDescription } from "~/client/components/ui/alert"; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from "~/client/components/ui/alert-dialog"; +import { Badge } from "~/client/components/ui/badge"; +import { Button } from "~/client/components/ui/button"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "~/client/components/ui/dialog"; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "~/client/components/ui/form"; +import { Input } from "~/client/components/ui/input"; +import { Label } from "~/client/components/ui/label"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "~/client/components/ui/select"; +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "~/client/components/ui/table"; +import { authClient } from "~/client/lib/auth-client"; +import { parseError } from "~/client/lib/errors"; +import { useOrganizationContext } from "~/client/hooks/use-org-context"; +import { formatDateWithMonth } from "~/client/lib/datetime"; +import { getOrigin } from "~/client/functions/get-origin"; + +const ssoProviderSchema = type({ + providerId: "string>=1", + issuer: "string>=1", + domain: "string>=1", + clientId: "string>=1", + clientSecret: "string>=1", + discoveryEndpoint: "string>=1", +}); + +type ProviderForm = typeof ssoProviderSchema.infer; +type InvitationRole = "member" | "admin" | "owner"; + +export function SsoSettingsSection() { + const origin = getOrigin(); + const { activeOrganization } = useOrganizationContext(); + const [isRegisterProviderDialogOpen, setIsRegisterProviderDialogOpen] = useState(false); + const [inviteEmail, setInviteEmail] = useState(""); + const [inviteRole, setInviteRole] = useState("member"); + + const form = useForm({ + resolver: arktypeResolver(ssoProviderSchema), + defaultValues: { + providerId: "", + issuer: "", + domain: "", + clientId: "", + clientSecret: "", + discoveryEndpoint: "", + }, + }); + + const { data } = useSuspenseQuery({ + ...getSsoSettingsOptions(), + }); + + const providers = data.providers; + const invitations = data.invitations; + + const registerProviderMutation = useMutation({ + mutationFn: async (formData: ProviderForm) => { + if (!activeOrganization) { + throw new Error("No active organization found in session"); + } + + const { error } = await authClient.sso.register({ + providerId: formData.providerId, + issuer: formData.issuer, + domain: formData.domain, + organizationId: activeOrganization.id, + oidcConfig: { + clientId: formData.clientId, + clientSecret: formData.clientSecret, + discoveryEndpoint: formData.discoveryEndpoint, + scopes: ["openid", "email", "profile"], + }, + }); + + if (error) throw error; + }, + onSuccess: () => { + toast.success("SSO provider registered successfully"); + form.reset(); + setIsRegisterProviderDialogOpen(false); + }, + onError: (error: unknown) => { + toast.error("Failed to register provider", { description: parseError(error)?.message }); + }, + }); + + const deleteProviderMutation = useMutation({ + ...deleteSsoProviderMutation(), + onSuccess: () => { + toast.success("SSO provider deleted"); + }, + onError: (error) => { + toast.error("Failed to delete provider", { description: parseError(error)?.message }); + }, + }); + + const inviteMemberMutation = useMutation({ + mutationFn: async () => { + if (!activeOrganization) { + throw new Error("No active organization found in session"); + } + + const normalizedEmail = inviteEmail.trim().toLowerCase(); + if (!normalizedEmail) { + throw new Error("Email is required"); + } + + const { error } = await authClient.organization.inviteMember({ + email: normalizedEmail, + role: inviteRole, + organizationId: activeOrganization.id, + }); + + if (error) { + throw error; + } + }, + onSuccess: () => { + toast.success("Invitation created"); + setInviteEmail(""); + setInviteRole("member"); + }, + onError: (error: unknown) => { + toast.error("Failed to create invitation", { description: parseError(error)?.message }); + }, + }); + + const cancelInvitationMutation = useMutation({ + mutationFn: async (invitationId: string) => { + const { error } = await authClient.organization.cancelInvitation({ invitationId }); + if (error) { + throw error; + } + }, + onSuccess: () => { + toast.success("Invitation cancelled"); + }, + onError: (error: unknown) => { + toast.error("Failed to cancel invitation", { description: parseError(error)?.message }); + }, + }); + + const deleteInvitationMutation = useMutation({ + ...deleteSsoInvitationMutation(), + onSuccess: () => { + toast.success("Invitation deleted"); + }, + onError: (error) => { + toast.error("Failed to delete invitation", { description: parseError(error)?.message }); + }, + }); + + return ( +
+
+
+
+

Registered providers

+

Manage identity providers used for organization sign-in.

+
+ + + + + + + + + Register SSO provider + Connect an OIDC provider for the active organization. + + +
+ registerProviderMutation.mutate(values))} + className="space-y-4" + > +
+ ( + + Provider ID + + + + Unique identifier used in callback URLs. + + + )} + /> + + ( + + Organization Domain + + + + Used to discover providers during login. + + + )} + /> + + ( + + Issuer URL + + + + + + )} + /> + + ( + + Discovery Endpoint + + + + + + )} + /> + + ( + + Client ID + + + + + + )} + /> + + ( + + Client Secret + + + + + + )} + /> +
+ + {!activeOrganization ? ( + + + No active organization found. Select an organization before registering an SSO provider. + + + ) : null} + +
+ +
+
+ +
+
+
+ +
+ + + + Provider ID + Domain + Issuer + Type + Callback URL + Actions + + + + {providers && providers.length > 0 ? ( + providers.map((provider) => ( + + {provider.providerId} + {provider.domain} + {provider.issuer} + +
+ + {provider.type} + +
+
+ + e.currentTarget.select()} + /> + + + + + + + + + Delete SSO provider + + Are you sure you want to delete the SSO provider {provider.providerId}? + This action cannot be undone. + + + + Cancel + + deleteProviderMutation.mutate({ path: { providerId: provider.providerId } }) + } + > + Delete + + + + + +
+ )) + ) : ( + + + No providers registered yet. + + + )} +
+
+
+
+ +
+
+

Invite-only access

+

+ Users must be invited or already have an account before they can sign in using SSO. +

+
+ +
+
+ + setInviteEmail(event.target.value)} + placeholder="teammate@example.com" + disabled={!activeOrganization || inviteMemberMutation.isPending} + /> +
+ +
+ + +
+ +
+ +
+
+ +
+ + + + Email + Role + Status + Expires + Actions + + + + {invitations.length > 0 ? ( + invitations.map((invitation) => ( + + {invitation.email} + {invitation.role} + + + {invitation.status} + + + {formatDateWithMonth(invitation.expiresAt)} + + {invitation.status === "pending" ? ( + + ) : ( + + )} + + + )) + ) : ( + + + No invitations yet. + + + )} + +
+
+
+
+ ); +} diff --git a/app/client/modules/settings/components/user-management.tsx b/app/client/modules/settings/components/user-management.tsx index d64ac359..01797052 100644 --- a/app/client/modules/settings/components/user-management.tsx +++ b/app/client/modules/settings/components/user-management.tsx @@ -1,5 +1,5 @@ -import { useMutation, useQuery } from "@tanstack/react-query"; -import { Shield, ShieldAlert, UserMinus, UserCheck, Trash2, Search, AlertTriangle } from "lucide-react"; +import { useMutation, useQuery, useSuspenseQuery } from "@tanstack/react-query"; +import { Shield, ShieldAlert, UserCheck, Trash2, Search, AlertTriangle, Ban } from "lucide-react"; import { useState } from "react"; import { toast } from "sonner"; import { authClient } from "~/client/lib/auth-client"; @@ -17,12 +17,9 @@ import { DialogTitle, } from "~/client/components/ui/dialog"; import { CreateUserDialog } from "./create-user-dialog"; -import { getUserDeletionImpactOptions } from "~/client/api-client/@tanstack/react-query.gen"; - -export function UserManagement() { - const { data: session } = authClient.useSession(); - const currentUser = session?.user; +import { getAdminUsersOptions, getUserDeletionImpactOptions } from "~/client/api-client/@tanstack/react-query.gen"; +export function UserManagement({ currentUser }: { currentUser: { id: string } | undefined | null }) { const [search, setSearch] = useState(""); const [userToDelete, setUserToDelete] = useState(null); const [userToBan, setUserToBan] = useState<{ id: string; name: string; isBanned: boolean } | null>(null); @@ -32,14 +29,7 @@ export function UserManagement() { enabled: Boolean(userToDelete), }); - const { data, isLoading, refetch } = useQuery({ - queryKey: ["admin-users"], - queryFn: async () => { - const { data, error } = await authClient.admin.listUsers({ query: { limit: 100 } }); - if (error) throw error; - return data; - }, - }); + const { data } = useSuspenseQuery({ ...getAdminUsersOptions() }); const setRoleMutation = useMutation({ mutationFn: async ({ userId, role }: { userId: string; role: "user" | "admin" }) => { @@ -48,10 +38,9 @@ export function UserManagement() { }, onSuccess: () => { toast.success("User role updated successfully"); - void refetch(); }, - onError: (err: any) => { - toast.error("Failed to update role", { description: err.message }); + onError: (error) => { + toast.error("Failed to update role", { description: error.message }); }, }); @@ -62,36 +51,36 @@ export function UserManagement() { }, onSuccess: () => { toast.success("User ban status updated successfully"); - void refetch(); }, onMutate: () => { setUserToBan(null); }, - onError: (err: any) => { - toast.error("Failed to update ban status", { description: err.message }); + onError: (error) => { + toast.error("Failed to update ban status", { description: error.message }); }, }); - const filteredUsers = data?.users.filter( - (user) => - user.name.toLowerCase().includes(search.toLowerCase()) || - user.email.toLowerCase().includes(search.toLowerCase()) || - (user as any).username?.toLowerCase().includes(search.toLowerCase()), - ); - - const handleDeleteUser = async () => { - if (!userToDelete) return; - - try { - const { error } = await authClient.admin.removeUser({ userId: userToDelete }); + const deleteUser = useMutation({ + mutationFn: async (userId: string) => { + const { error } = await authClient.admin.removeUser({ userId }); if (error) throw error; + }, + onSuccess: () => { toast.success("User deleted successfully"); setUserToDelete(null); - void refetch(); - } catch (err: any) { - toast.error("Failed to delete user", { description: err.message }); - } - }; + }, + onError: (error) => { + toast.error("Failed to delete user", { description: error.message }); + }, + }); + + const normalizedSearch = search.toLowerCase(); + const filteredUsers = data.users.filter((user) => { + const name = user.name?.toLowerCase() ?? ""; + const email = user.email.toLowerCase(); + + return name.includes(normalizedSearch) || email.includes(normalizedSearch); + }); return (
@@ -105,7 +94,7 @@ export function UserManagement() { onChange={(e) => setSearch(e.target.value)} />
- void refetch()} /> +
@@ -119,21 +108,18 @@ export function UserManagement() { - - - Loading users... - - - 0) })}> - - No users found. - - - {filteredUsers?.map((user) => ( + {filteredUsers.length === 0 ? ( + + + No users found. + + + ) : null} + {filteredUsers.map((user) => (
- {user.name} + {user.name ?? user.email} {user.email}
@@ -172,20 +158,20 @@ export function UserManagement() { - @@ -267,14 +253,14 @@ export function UserManagement() { diff --git a/app/client/modules/settings/routes/settings.tsx b/app/client/modules/settings/routes/settings.tsx index d46d2360..6b74edcd 100644 --- a/app/client/modules/settings/routes/settings.tsx +++ b/app/client/modules/settings/routes/settings.tsx @@ -27,6 +27,7 @@ import { type AppContext } from "~/context"; import { TwoFactorSection } from "../components/two-factor-section"; import { UserManagement } from "../components/user-management"; import { useNavigate, useSearch } from "@tanstack/react-router"; +import { SsoSettingsSection } from "../components/sso/sso-settings-section"; type Props = { appContext: AppContext; @@ -165,7 +166,7 @@ export function SettingsPage({ appContext }: Props) { Account - {isAdmin && Users} + {isAdmin && Users & Authentication} {isAdmin && System} @@ -307,7 +308,7 @@ export function SettingsPage({ appContext }: Props) { {isAdmin && ( - +
@@ -316,7 +317,20 @@ export function SettingsPage({ appContext }: Props) { Manage users, roles and permissions
- + +
+ + +
+ + + Single Sign-On + + Configure OIDC provider settings +
+ + +
)} diff --git a/app/context.ts b/app/context.ts index fb654db3..0ae36afd 100644 --- a/app/context.ts +++ b/app/context.ts @@ -2,6 +2,7 @@ type User = { id: string; email: string; username: string; + name: string; hasDownloadedResticPassword: boolean; twoFactorEnabled?: boolean | null; role?: string | null | undefined; diff --git a/app/drizzle/20260214144113_mighty_meggan/migration.sql b/app/drizzle/20260214144113_mighty_meggan/migration.sql new file mode 100644 index 00000000..a4e44bf3 --- /dev/null +++ b/app/drizzle/20260214144113_mighty_meggan/migration.sql @@ -0,0 +1,18 @@ +CREATE TABLE `sso_provider` ( + `id` text PRIMARY KEY, + `provider_id` text NOT NULL, + `organization_id` text NOT NULL, + `user_id` text NOT NULL, + `issuer` text NOT NULL, + `domain` text NOT NULL, + `oidc_config` text, + `saml_config` text, + `created_at` integer DEFAULT (unixepoch() * 1000) NOT NULL, + `updated_at` integer DEFAULT (unixepoch() * 1000) NOT NULL, + CONSTRAINT `fk_sso_provider_organization_id_organization_id_fk` FOREIGN KEY (`organization_id`) REFERENCES `organization`(`id`) ON DELETE CASCADE, + CONSTRAINT `fk_sso_provider_user_id_users_table_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users_table`(`id`) ON DELETE CASCADE +); +--> statement-breakpoint +CREATE UNIQUE INDEX `sso_provider_provider_id_uidx` ON `sso_provider` (`provider_id`);--> statement-breakpoint +CREATE UNIQUE INDEX `sso_provider_organization_id_uidx` ON `sso_provider` (`organization_id`);--> statement-breakpoint +CREATE INDEX `sso_provider_domain_idx` ON `sso_provider` (`domain`); \ No newline at end of file diff --git a/app/drizzle/20260214144113_mighty_meggan/snapshot.json b/app/drizzle/20260214144113_mighty_meggan/snapshot.json new file mode 100644 index 00000000..2b67103b --- /dev/null +++ b/app/drizzle/20260214144113_mighty_meggan/snapshot.json @@ -0,0 +1,2210 @@ +{ + "version": "7", + "dialect": "sqlite", + "id": "ab028cd7-c0cb-44f4-843b-37e95ab3c667", + "prevIds": ["3a308c54-d950-464f-9490-fee06985fbeb"], + "ddl": [ + { + "name": "account", + "entityType": "tables" + }, + { + "name": "app_metadata", + "entityType": "tables" + }, + { + "name": "backup_schedule_mirrors_table", + "entityType": "tables" + }, + { + "name": "backup_schedule_notifications_table", + "entityType": "tables" + }, + { + "name": "backup_schedules_table", + "entityType": "tables" + }, + { + "name": "invitation", + "entityType": "tables" + }, + { + "name": "member", + "entityType": "tables" + }, + { + "name": "notification_destinations_table", + "entityType": "tables" + }, + { + "name": "organization", + "entityType": "tables" + }, + { + "name": "repositories_table", + "entityType": "tables" + }, + { + "name": "sessions_table", + "entityType": "tables" + }, + { + "name": "sso_provider", + "entityType": "tables" + }, + { + "name": "two_factor", + "entityType": "tables" + }, + { + "name": "users_table", + "entityType": "tables" + }, + { + "name": "verification", + "entityType": "tables" + }, + { + "name": "volumes_table", + "entityType": "tables" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "account" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "account_id", + "entityType": "columns", + "table": "account" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "provider_id", + "entityType": "columns", + "table": "account" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "account" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "access_token", + "entityType": "columns", + "table": "account" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "refresh_token", + "entityType": "columns", + "table": "account" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id_token", + "entityType": "columns", + "table": "account" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "access_token_expires_at", + "entityType": "columns", + "table": "account" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "refresh_token_expires_at", + "entityType": "columns", + "table": "account" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "scope", + "entityType": "columns", + "table": "account" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "password", + "entityType": "columns", + "table": "account" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch() * 1000)", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "account" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch() * 1000)", + "generated": null, + "name": "updated_at", + "entityType": "columns", + "table": "account" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "key", + "entityType": "columns", + "table": "app_metadata" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "value", + "entityType": "columns", + "table": "app_metadata" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch() * 1000)", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "app_metadata" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch() * 1000)", + "generated": null, + "name": "updated_at", + "entityType": "columns", + "table": "app_metadata" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": true, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "backup_schedule_mirrors_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "schedule_id", + "entityType": "columns", + "table": "backup_schedule_mirrors_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "repository_id", + "entityType": "columns", + "table": "backup_schedule_mirrors_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "true", + "generated": null, + "name": "enabled", + "entityType": "columns", + "table": "backup_schedule_mirrors_table" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "last_copy_at", + "entityType": "columns", + "table": "backup_schedule_mirrors_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "last_copy_status", + "entityType": "columns", + "table": "backup_schedule_mirrors_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "last_copy_error", + "entityType": "columns", + "table": "backup_schedule_mirrors_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch() * 1000)", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "backup_schedule_mirrors_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "schedule_id", + "entityType": "columns", + "table": "backup_schedule_notifications_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "destination_id", + "entityType": "columns", + "table": "backup_schedule_notifications_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "notify_on_start", + "entityType": "columns", + "table": "backup_schedule_notifications_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "notify_on_success", + "entityType": "columns", + "table": "backup_schedule_notifications_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "true", + "generated": null, + "name": "notify_on_warning", + "entityType": "columns", + "table": "backup_schedule_notifications_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "true", + "generated": null, + "name": "notify_on_failure", + "entityType": "columns", + "table": "backup_schedule_notifications_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch() * 1000)", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "backup_schedule_notifications_table" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": true, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "backup_schedules_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "short_id", + "entityType": "columns", + "table": "backup_schedules_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "name", + "entityType": "columns", + "table": "backup_schedules_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "volume_id", + "entityType": "columns", + "table": "backup_schedules_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "repository_id", + "entityType": "columns", + "table": "backup_schedules_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "true", + "generated": null, + "name": "enabled", + "entityType": "columns", + "table": "backup_schedules_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "cron_expression", + "entityType": "columns", + "table": "backup_schedules_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "retention_policy", + "entityType": "columns", + "table": "backup_schedules_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": "'[]'", + "generated": null, + "name": "exclude_patterns", + "entityType": "columns", + "table": "backup_schedules_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": "'[]'", + "generated": null, + "name": "exclude_if_present", + "entityType": "columns", + "table": "backup_schedules_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": "'[]'", + "generated": null, + "name": "include_patterns", + "entityType": "columns", + "table": "backup_schedules_table" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "last_backup_at", + "entityType": "columns", + "table": "backup_schedules_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "last_backup_status", + "entityType": "columns", + "table": "backup_schedules_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "last_backup_error", + "entityType": "columns", + "table": "backup_schedules_table" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "next_backup_at", + "entityType": "columns", + "table": "backup_schedules_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "one_file_system", + "entityType": "columns", + "table": "backup_schedules_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "0", + "generated": null, + "name": "sort_order", + "entityType": "columns", + "table": "backup_schedules_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch() * 1000)", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "backup_schedules_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch() * 1000)", + "generated": null, + "name": "updated_at", + "entityType": "columns", + "table": "backup_schedules_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "organization_id", + "entityType": "columns", + "table": "backup_schedules_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "invitation" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "organization_id", + "entityType": "columns", + "table": "invitation" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "email", + "entityType": "columns", + "table": "invitation" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "role", + "entityType": "columns", + "table": "invitation" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": "'pending'", + "generated": null, + "name": "status", + "entityType": "columns", + "table": "invitation" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "expires_at", + "entityType": "columns", + "table": "invitation" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "invitation" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "inviter_id", + "entityType": "columns", + "table": "invitation" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "member" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "organization_id", + "entityType": "columns", + "table": "member" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "member" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": "'member'", + "generated": null, + "name": "role", + "entityType": "columns", + "table": "member" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "member" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": true, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "notification_destinations_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "name", + "entityType": "columns", + "table": "notification_destinations_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "true", + "generated": null, + "name": "enabled", + "entityType": "columns", + "table": "notification_destinations_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "type", + "entityType": "columns", + "table": "notification_destinations_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "config", + "entityType": "columns", + "table": "notification_destinations_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch() * 1000)", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "notification_destinations_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch() * 1000)", + "generated": null, + "name": "updated_at", + "entityType": "columns", + "table": "notification_destinations_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "organization_id", + "entityType": "columns", + "table": "notification_destinations_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "organization" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "name", + "entityType": "columns", + "table": "organization" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "slug", + "entityType": "columns", + "table": "organization" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "logo", + "entityType": "columns", + "table": "organization" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "organization" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "metadata", + "entityType": "columns", + "table": "organization" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "repositories_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "short_id", + "entityType": "columns", + "table": "repositories_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "name", + "entityType": "columns", + "table": "repositories_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "type", + "entityType": "columns", + "table": "repositories_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "config", + "entityType": "columns", + "table": "repositories_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": "'auto'", + "generated": null, + "name": "compression_mode", + "entityType": "columns", + "table": "repositories_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": "'unknown'", + "generated": null, + "name": "status", + "entityType": "columns", + "table": "repositories_table" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "last_checked", + "entityType": "columns", + "table": "repositories_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "last_error", + "entityType": "columns", + "table": "repositories_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "doctor_result", + "entityType": "columns", + "table": "repositories_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "upload_limit_enabled", + "entityType": "columns", + "table": "repositories_table" + }, + { + "type": "real", + "notNull": true, + "autoincrement": false, + "default": "1", + "generated": null, + "name": "upload_limit_value", + "entityType": "columns", + "table": "repositories_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": "'Mbps'", + "generated": null, + "name": "upload_limit_unit", + "entityType": "columns", + "table": "repositories_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "download_limit_enabled", + "entityType": "columns", + "table": "repositories_table" + }, + { + "type": "real", + "notNull": true, + "autoincrement": false, + "default": "1", + "generated": null, + "name": "download_limit_value", + "entityType": "columns", + "table": "repositories_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": "'Mbps'", + "generated": null, + "name": "download_limit_unit", + "entityType": "columns", + "table": "repositories_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch() * 1000)", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "repositories_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch() * 1000)", + "generated": null, + "name": "updated_at", + "entityType": "columns", + "table": "repositories_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "organization_id", + "entityType": "columns", + "table": "repositories_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "sessions_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "sessions_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "token", + "entityType": "columns", + "table": "sessions_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "expires_at", + "entityType": "columns", + "table": "sessions_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch() * 1000)", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "sessions_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch() * 1000)", + "generated": null, + "name": "updated_at", + "entityType": "columns", + "table": "sessions_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "ip_address", + "entityType": "columns", + "table": "sessions_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "user_agent", + "entityType": "columns", + "table": "sessions_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "impersonated_by", + "entityType": "columns", + "table": "sessions_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "active_organization_id", + "entityType": "columns", + "table": "sessions_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "sso_provider" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "provider_id", + "entityType": "columns", + "table": "sso_provider" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "organization_id", + "entityType": "columns", + "table": "sso_provider" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "sso_provider" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "issuer", + "entityType": "columns", + "table": "sso_provider" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "domain", + "entityType": "columns", + "table": "sso_provider" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "oidc_config", + "entityType": "columns", + "table": "sso_provider" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "saml_config", + "entityType": "columns", + "table": "sso_provider" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch() * 1000)", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "sso_provider" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch() * 1000)", + "generated": null, + "name": "updated_at", + "entityType": "columns", + "table": "sso_provider" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "two_factor" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "secret", + "entityType": "columns", + "table": "two_factor" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "backup_codes", + "entityType": "columns", + "table": "two_factor" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "user_id", + "entityType": "columns", + "table": "two_factor" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "users_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "username", + "entityType": "columns", + "table": "users_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "password_hash", + "entityType": "columns", + "table": "users_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "has_downloaded_restic_password", + "entityType": "columns", + "table": "users_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch() * 1000)", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "users_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch() * 1000)", + "generated": null, + "name": "updated_at", + "entityType": "columns", + "table": "users_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "name", + "entityType": "columns", + "table": "users_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "email", + "entityType": "columns", + "table": "users_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "email_verified", + "entityType": "columns", + "table": "users_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "image", + "entityType": "columns", + "table": "users_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "display_username", + "entityType": "columns", + "table": "users_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "two_factor_enabled", + "entityType": "columns", + "table": "users_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": "'user'", + "generated": null, + "name": "role", + "entityType": "columns", + "table": "users_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "false", + "generated": null, + "name": "banned", + "entityType": "columns", + "table": "users_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "ban_reason", + "entityType": "columns", + "table": "users_table" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "ban_expires", + "entityType": "columns", + "table": "users_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "verification" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "identifier", + "entityType": "columns", + "table": "verification" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "value", + "entityType": "columns", + "table": "verification" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "expires_at", + "entityType": "columns", + "table": "verification" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch() * 1000)", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "verification" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch() * 1000)", + "generated": null, + "name": "updated_at", + "entityType": "columns", + "table": "verification" + }, + { + "type": "integer", + "notNull": false, + "autoincrement": true, + "default": null, + "generated": null, + "name": "id", + "entityType": "columns", + "table": "volumes_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "short_id", + "entityType": "columns", + "table": "volumes_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "name", + "entityType": "columns", + "table": "volumes_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "type", + "entityType": "columns", + "table": "volumes_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": "'unmounted'", + "generated": null, + "name": "status", + "entityType": "columns", + "table": "volumes_table" + }, + { + "type": "text", + "notNull": false, + "autoincrement": false, + "default": null, + "generated": null, + "name": "last_error", + "entityType": "columns", + "table": "volumes_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch() * 1000)", + "generated": null, + "name": "last_health_check", + "entityType": "columns", + "table": "volumes_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch() * 1000)", + "generated": null, + "name": "created_at", + "entityType": "columns", + "table": "volumes_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "(unixepoch() * 1000)", + "generated": null, + "name": "updated_at", + "entityType": "columns", + "table": "volumes_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "config", + "entityType": "columns", + "table": "volumes_table" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": "true", + "generated": null, + "name": "auto_remount", + "entityType": "columns", + "table": "volumes_table" + }, + { + "type": "text", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "organization_id", + "entityType": "columns", + "table": "volumes_table" + }, + { + "columns": ["user_id"], + "tableTo": "users_table", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "account_user_id_users_table_id_fk", + "entityType": "fks", + "table": "account" + }, + { + "columns": ["schedule_id"], + "tableTo": "backup_schedules_table", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk", + "entityType": "fks", + "table": "backup_schedule_mirrors_table" + }, + { + "columns": ["repository_id"], + "tableTo": "repositories_table", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "backup_schedule_mirrors_table_repository_id_repositories_table_id_fk", + "entityType": "fks", + "table": "backup_schedule_mirrors_table" + }, + { + "columns": ["schedule_id"], + "tableTo": "backup_schedules_table", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk", + "entityType": "fks", + "table": "backup_schedule_notifications_table" + }, + { + "columns": ["destination_id"], + "tableTo": "notification_destinations_table", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk", + "entityType": "fks", + "table": "backup_schedule_notifications_table" + }, + { + "columns": ["volume_id"], + "tableTo": "volumes_table", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "backup_schedules_table_volume_id_volumes_table_id_fk", + "entityType": "fks", + "table": "backup_schedules_table" + }, + { + "columns": ["repository_id"], + "tableTo": "repositories_table", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "backup_schedules_table_repository_id_repositories_table_id_fk", + "entityType": "fks", + "table": "backup_schedules_table" + }, + { + "columns": ["organization_id"], + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "backup_schedules_table_organization_id_organization_id_fk", + "entityType": "fks", + "table": "backup_schedules_table" + }, + { + "columns": ["organization_id"], + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "invitation_organization_id_organization_id_fk", + "entityType": "fks", + "table": "invitation" + }, + { + "columns": ["inviter_id"], + "tableTo": "users_table", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "invitation_inviter_id_users_table_id_fk", + "entityType": "fks", + "table": "invitation" + }, + { + "columns": ["organization_id"], + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "member_organization_id_organization_id_fk", + "entityType": "fks", + "table": "member" + }, + { + "columns": ["user_id"], + "tableTo": "users_table", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "member_user_id_users_table_id_fk", + "entityType": "fks", + "table": "member" + }, + { + "columns": ["organization_id"], + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "notification_destinations_table_organization_id_organization_id_fk", + "entityType": "fks", + "table": "notification_destinations_table" + }, + { + "columns": ["organization_id"], + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "repositories_table_organization_id_organization_id_fk", + "entityType": "fks", + "table": "repositories_table" + }, + { + "columns": ["user_id"], + "tableTo": "users_table", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "sessions_table_user_id_users_table_id_fk", + "entityType": "fks", + "table": "sessions_table" + }, + { + "columns": ["organization_id"], + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_sso_provider_organization_id_organization_id_fk", + "entityType": "fks", + "table": "sso_provider" + }, + { + "columns": ["user_id"], + "tableTo": "users_table", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "fk_sso_provider_user_id_users_table_id_fk", + "entityType": "fks", + "table": "sso_provider" + }, + { + "columns": ["user_id"], + "tableTo": "users_table", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "two_factor_user_id_users_table_id_fk", + "entityType": "fks", + "table": "two_factor" + }, + { + "columns": ["organization_id"], + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "nameExplicit": false, + "name": "volumes_table_organization_id_organization_id_fk", + "entityType": "fks", + "table": "volumes_table" + }, + { + "columns": ["schedule_id", "destination_id"], + "nameExplicit": false, + "name": "backup_schedule_notifications_table_schedule_id_destination_id_pk", + "entityType": "pks", + "table": "backup_schedule_notifications_table" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "account_pk", + "table": "account", + "entityType": "pks" + }, + { + "columns": ["key"], + "nameExplicit": false, + "name": "app_metadata_pk", + "table": "app_metadata", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "backup_schedule_mirrors_table_pk", + "table": "backup_schedule_mirrors_table", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "backup_schedules_table_pk", + "table": "backup_schedules_table", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "invitation_pk", + "table": "invitation", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "member_pk", + "table": "member", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "notification_destinations_table_pk", + "table": "notification_destinations_table", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "organization_pk", + "table": "organization", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "repositories_table_pk", + "table": "repositories_table", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "sessions_table_pk", + "table": "sessions_table", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "sso_provider_pk", + "table": "sso_provider", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "two_factor_pk", + "table": "two_factor", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "users_table_pk", + "table": "users_table", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "verification_pk", + "table": "verification", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "volumes_table_pk", + "table": "volumes_table", + "entityType": "pks" + }, + { + "columns": [ + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "account_userId_idx", + "entityType": "indexes", + "table": "account" + }, + { + "columns": [ + { + "value": "organization_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "invitation_organizationId_idx", + "entityType": "indexes", + "table": "invitation" + }, + { + "columns": [ + { + "value": "email", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "invitation_email_idx", + "entityType": "indexes", + "table": "invitation" + }, + { + "columns": [ + { + "value": "organization_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "member_organizationId_idx", + "entityType": "indexes", + "table": "member" + }, + { + "columns": [ + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "member_userId_idx", + "entityType": "indexes", + "table": "member" + }, + { + "columns": [ + { + "value": "organization_id", + "isExpression": false + }, + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": true, + "where": null, + "origin": "manual", + "name": "member_org_user_uidx", + "entityType": "indexes", + "table": "member" + }, + { + "columns": [ + { + "value": "slug", + "isExpression": false + } + ], + "isUnique": true, + "where": null, + "origin": "manual", + "name": "organization_slug_uidx", + "entityType": "indexes", + "table": "organization" + }, + { + "columns": [ + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "sessionsTable_userId_idx", + "entityType": "indexes", + "table": "sessions_table" + }, + { + "columns": [ + { + "value": "provider_id", + "isExpression": false + } + ], + "isUnique": true, + "where": null, + "origin": "manual", + "name": "sso_provider_provider_id_uidx", + "entityType": "indexes", + "table": "sso_provider" + }, + { + "columns": [ + { + "value": "organization_id", + "isExpression": false + } + ], + "isUnique": true, + "where": null, + "origin": "manual", + "name": "sso_provider_organization_id_uidx", + "entityType": "indexes", + "table": "sso_provider" + }, + { + "columns": [ + { + "value": "domain", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "sso_provider_domain_idx", + "entityType": "indexes", + "table": "sso_provider" + }, + { + "columns": [ + { + "value": "secret", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "twoFactor_secret_idx", + "entityType": "indexes", + "table": "two_factor" + }, + { + "columns": [ + { + "value": "user_id", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "twoFactor_userId_idx", + "entityType": "indexes", + "table": "two_factor" + }, + { + "columns": [ + { + "value": "identifier", + "isExpression": false + } + ], + "isUnique": false, + "where": null, + "origin": "manual", + "name": "verification_identifier_idx", + "entityType": "indexes", + "table": "verification" + }, + { + "columns": ["schedule_id", "repository_id"], + "nameExplicit": false, + "name": "backup_schedule_mirrors_table_schedule_id_repository_id_unique", + "entityType": "uniques", + "table": "backup_schedule_mirrors_table" + }, + { + "columns": ["name", "organization_id"], + "nameExplicit": false, + "name": "volumes_table_name_organization_id_unique", + "entityType": "uniques", + "table": "volumes_table" + }, + { + "columns": ["short_id"], + "nameExplicit": false, + "name": "backup_schedules_table_short_id_unique", + "entityType": "uniques", + "table": "backup_schedules_table" + }, + { + "columns": ["short_id"], + "nameExplicit": false, + "name": "repositories_table_short_id_unique", + "entityType": "uniques", + "table": "repositories_table" + }, + { + "columns": ["token"], + "nameExplicit": false, + "name": "sessions_table_token_unique", + "entityType": "uniques", + "table": "sessions_table" + }, + { + "columns": ["username"], + "nameExplicit": false, + "name": "users_table_username_unique", + "entityType": "uniques", + "table": "users_table" + }, + { + "columns": ["email"], + "nameExplicit": false, + "name": "users_table_email_unique", + "entityType": "uniques", + "table": "users_table" + }, + { + "columns": ["short_id"], + "nameExplicit": false, + "name": "volumes_table_short_id_unique", + "entityType": "uniques", + "table": "volumes_table" + } + ], + "renames": [] +} diff --git a/app/middleware/auth.ts b/app/middleware/auth.ts index 6d987d9a..dbdda8e9 100644 --- a/app/middleware/auth.ts +++ b/app/middleware/auth.ts @@ -4,13 +4,20 @@ import { auth } from "~/server/lib/auth"; import { getRequestHeaders } from "@tanstack/react-start/server"; import { authService } from "~/server/modules/auth/auth.service"; +function isAuthRoute(pathname: string): boolean { + if (pathname === "/onboarding") return true; + if (pathname === "/login") return true; + if (pathname.match(/^\/login\/[^/]+$/)) return true; + if (pathname.match(/^\/login\/[^/]+\/error$/)) return true; + return false; +} + export const authMiddleware = createMiddleware().server(async ({ next, request }) => { const headers = getRequestHeaders(); const session = await auth.api.getSession({ headers }); + const pathname = new URL(request.url).pathname; - const isAuthRoute = ["/login", "/onboarding"].includes(new URL(request.url).pathname); - - if (!session?.user?.id && !isAuthRoute) { + if (!session?.user?.id && !isAuthRoute(pathname)) { const hasUsers = await authService.hasUsers(); if (!hasUsers) { throw redirect({ to: "/onboarding" }); @@ -20,8 +27,11 @@ export const authMiddleware = createMiddleware().server(async ({ next, request } } if (session?.user?.id) { - if (isAuthRoute) { - throw redirect({ to: "/" }); + if (isAuthRoute(pathname)) { + if (!session.user.hasDownloadedResticPassword) { + throw redirect({ to: "/download-recovery-key" }); + } + throw redirect({ to: "/volumes" }); } } diff --git a/app/routeTree.gen.ts b/app/routeTree.gen.ts index c9067284..d771c908 100644 --- a/app/routeTree.gen.ts +++ b/app/routeTree.gen.ts @@ -10,6 +10,7 @@ import { Route as rootRouteImport } from './routes/__root' import { Route as dashboardRouteRouteImport } from './routes/(dashboard)/route' +import { Route as authRouteRouteImport } from './routes/(auth)/route' import { Route as IndexRouteImport } from './routes/index' import { Route as ApiSplatRouteImport } from './routes/api.$' import { Route as authOnboardingRouteImport } from './routes/(auth)/onboarding' @@ -22,12 +23,15 @@ import { Route as dashboardNotificationsIndexRouteImport } from './routes/(dashb import { Route as dashboardBackupsIndexRouteImport } from './routes/(dashboard)/backups/index' import { Route as dashboardVolumesCreateRouteImport } from './routes/(dashboard)/volumes/create' import { Route as dashboardVolumesVolumeIdRouteImport } from './routes/(dashboard)/volumes/$volumeId' +import { Route as dashboardSettingsSsoLinkRouteImport } from './routes/(dashboard)/settings/sso-link' import { Route as dashboardRepositoriesCreateRouteImport } from './routes/(dashboard)/repositories/create' import { Route as dashboardNotificationsCreateRouteImport } from './routes/(dashboard)/notifications/create' import { Route as dashboardNotificationsNotificationIdRouteImport } from './routes/(dashboard)/notifications/$notificationId' import { Route as dashboardBackupsCreateRouteImport } from './routes/(dashboard)/backups/create' +import { Route as authLoginErrorRouteImport } from './routes/(auth)/login.error' import { Route as dashboardRepositoriesRepositoryIdIndexRouteImport } from './routes/(dashboard)/repositories/$repositoryId/index' import { Route as dashboardBackupsBackupIdIndexRouteImport } from './routes/(dashboard)/backups/$backupId/index' +import { Route as dashboardSettingsSsoLinkErrorRouteImport } from './routes/(dashboard)/settings/sso-link.error' import { Route as dashboardRepositoriesRepositoryIdEditRouteImport } from './routes/(dashboard)/repositories/$repositoryId/edit' import { Route as dashboardRepositoriesRepositoryIdSnapshotIdIndexRouteImport } from './routes/(dashboard)/repositories/$repositoryId/$snapshotId/index' import { Route as dashboardRepositoriesRepositoryIdSnapshotIdRestoreRouteImport } from './routes/(dashboard)/repositories/$repositoryId/$snapshotId/restore' @@ -37,6 +41,10 @@ const dashboardRouteRoute = dashboardRouteRouteImport.update({ id: '/(dashboard)', getParentRoute: () => rootRouteImport, } as any) +const authRouteRoute = authRouteRouteImport.update({ + id: '/(auth)', + getParentRoute: () => rootRouteImport, +} as any) const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', @@ -48,19 +56,19 @@ const ApiSplatRoute = ApiSplatRouteImport.update({ getParentRoute: () => rootRouteImport, } as any) const authOnboardingRoute = authOnboardingRouteImport.update({ - id: '/(auth)/onboarding', + id: '/onboarding', path: '/onboarding', - getParentRoute: () => rootRouteImport, + getParentRoute: () => authRouteRoute, } as any) const authLoginRoute = authLoginRouteImport.update({ - id: '/(auth)/login', + id: '/login', path: '/login', - getParentRoute: () => rootRouteImport, + getParentRoute: () => authRouteRoute, } as any) const authDownloadRecoveryKeyRoute = authDownloadRecoveryKeyRouteImport.update({ - id: '/(auth)/download-recovery-key', + id: '/download-recovery-key', path: '/download-recovery-key', - getParentRoute: () => rootRouteImport, + getParentRoute: () => authRouteRoute, } as any) const dashboardVolumesIndexRoute = dashboardVolumesIndexRouteImport.update({ id: '/volumes/', @@ -100,6 +108,12 @@ const dashboardVolumesVolumeIdRoute = path: '/volumes/$volumeId', getParentRoute: () => dashboardRouteRoute, } as any) +const dashboardSettingsSsoLinkRoute = + dashboardSettingsSsoLinkRouteImport.update({ + id: '/settings/sso-link', + path: '/settings/sso-link', + getParentRoute: () => dashboardRouteRoute, + } as any) const dashboardRepositoriesCreateRoute = dashboardRepositoriesCreateRouteImport.update({ id: '/repositories/create', @@ -123,6 +137,11 @@ const dashboardBackupsCreateRoute = dashboardBackupsCreateRouteImport.update({ path: '/backups/create', getParentRoute: () => dashboardRouteRoute, } as any) +const authLoginErrorRoute = authLoginErrorRouteImport.update({ + id: '/error', + path: '/error', + getParentRoute: () => authLoginRoute, +} as any) const dashboardRepositoriesRepositoryIdIndexRoute = dashboardRepositoriesRepositoryIdIndexRouteImport.update({ id: '/repositories/$repositoryId/', @@ -135,6 +154,12 @@ const dashboardBackupsBackupIdIndexRoute = path: '/backups/$backupId/', getParentRoute: () => dashboardRouteRoute, } as any) +const dashboardSettingsSsoLinkErrorRoute = + dashboardSettingsSsoLinkErrorRouteImport.update({ + id: '/error', + path: '/error', + getParentRoute: () => dashboardSettingsSsoLinkRoute, + } as any) const dashboardRepositoriesRepositoryIdEditRoute = dashboardRepositoriesRepositoryIdEditRouteImport.update({ id: '/repositories/$repositoryId/edit', @@ -163,13 +188,15 @@ const dashboardBackupsBackupIdSnapshotIdRestoreRoute = export interface FileRoutesByFullPath { '/': typeof IndexRoute '/download-recovery-key': typeof authDownloadRecoveryKeyRoute - '/login': typeof authLoginRoute + '/login': typeof authLoginRouteWithChildren '/onboarding': typeof authOnboardingRoute '/api/$': typeof ApiSplatRoute + '/login/error': typeof authLoginErrorRoute '/backups/create': typeof dashboardBackupsCreateRoute '/notifications/$notificationId': typeof dashboardNotificationsNotificationIdRoute '/notifications/create': typeof dashboardNotificationsCreateRoute '/repositories/create': typeof dashboardRepositoriesCreateRoute + '/settings/sso-link': typeof dashboardSettingsSsoLinkRouteWithChildren '/volumes/$volumeId': typeof dashboardVolumesVolumeIdRoute '/volumes/create': typeof dashboardVolumesCreateRoute '/backups/': typeof dashboardBackupsIndexRoute @@ -178,6 +205,7 @@ export interface FileRoutesByFullPath { '/settings/': typeof dashboardSettingsIndexRoute '/volumes/': typeof dashboardVolumesIndexRoute '/repositories/$repositoryId/edit': typeof dashboardRepositoriesRepositoryIdEditRoute + '/settings/sso-link/error': typeof dashboardSettingsSsoLinkErrorRoute '/backups/$backupId/': typeof dashboardBackupsBackupIdIndexRoute '/repositories/$repositoryId/': typeof dashboardRepositoriesRepositoryIdIndexRoute '/backups/$backupId/$snapshotId/restore': typeof dashboardBackupsBackupIdSnapshotIdRestoreRoute @@ -187,13 +215,15 @@ export interface FileRoutesByFullPath { export interface FileRoutesByTo { '/': typeof IndexRoute '/download-recovery-key': typeof authDownloadRecoveryKeyRoute - '/login': typeof authLoginRoute + '/login': typeof authLoginRouteWithChildren '/onboarding': typeof authOnboardingRoute '/api/$': typeof ApiSplatRoute + '/login/error': typeof authLoginErrorRoute '/backups/create': typeof dashboardBackupsCreateRoute '/notifications/$notificationId': typeof dashboardNotificationsNotificationIdRoute '/notifications/create': typeof dashboardNotificationsCreateRoute '/repositories/create': typeof dashboardRepositoriesCreateRoute + '/settings/sso-link': typeof dashboardSettingsSsoLinkRouteWithChildren '/volumes/$volumeId': typeof dashboardVolumesVolumeIdRoute '/volumes/create': typeof dashboardVolumesCreateRoute '/backups': typeof dashboardBackupsIndexRoute @@ -202,6 +232,7 @@ export interface FileRoutesByTo { '/settings': typeof dashboardSettingsIndexRoute '/volumes': typeof dashboardVolumesIndexRoute '/repositories/$repositoryId/edit': typeof dashboardRepositoriesRepositoryIdEditRoute + '/settings/sso-link/error': typeof dashboardSettingsSsoLinkErrorRoute '/backups/$backupId': typeof dashboardBackupsBackupIdIndexRoute '/repositories/$repositoryId': typeof dashboardRepositoriesRepositoryIdIndexRoute '/backups/$backupId/$snapshotId/restore': typeof dashboardBackupsBackupIdSnapshotIdRestoreRoute @@ -211,15 +242,18 @@ export interface FileRoutesByTo { export interface FileRoutesById { __root__: typeof rootRouteImport '/': typeof IndexRoute + '/(auth)': typeof authRouteRouteWithChildren '/(dashboard)': typeof dashboardRouteRouteWithChildren '/(auth)/download-recovery-key': typeof authDownloadRecoveryKeyRoute - '/(auth)/login': typeof authLoginRoute + '/(auth)/login': typeof authLoginRouteWithChildren '/(auth)/onboarding': typeof authOnboardingRoute '/api/$': typeof ApiSplatRoute + '/(auth)/login/error': typeof authLoginErrorRoute '/(dashboard)/backups/create': typeof dashboardBackupsCreateRoute '/(dashboard)/notifications/$notificationId': typeof dashboardNotificationsNotificationIdRoute '/(dashboard)/notifications/create': typeof dashboardNotificationsCreateRoute '/(dashboard)/repositories/create': typeof dashboardRepositoriesCreateRoute + '/(dashboard)/settings/sso-link': typeof dashboardSettingsSsoLinkRouteWithChildren '/(dashboard)/volumes/$volumeId': typeof dashboardVolumesVolumeIdRoute '/(dashboard)/volumes/create': typeof dashboardVolumesCreateRoute '/(dashboard)/backups/': typeof dashboardBackupsIndexRoute @@ -228,6 +262,7 @@ export interface FileRoutesById { '/(dashboard)/settings/': typeof dashboardSettingsIndexRoute '/(dashboard)/volumes/': typeof dashboardVolumesIndexRoute '/(dashboard)/repositories/$repositoryId/edit': typeof dashboardRepositoriesRepositoryIdEditRoute + '/(dashboard)/settings/sso-link/error': typeof dashboardSettingsSsoLinkErrorRoute '/(dashboard)/backups/$backupId/': typeof dashboardBackupsBackupIdIndexRoute '/(dashboard)/repositories/$repositoryId/': typeof dashboardRepositoriesRepositoryIdIndexRoute '/(dashboard)/backups/$backupId/$snapshotId/restore': typeof dashboardBackupsBackupIdSnapshotIdRestoreRoute @@ -242,10 +277,12 @@ export interface FileRouteTypes { | '/login' | '/onboarding' | '/api/$' + | '/login/error' | '/backups/create' | '/notifications/$notificationId' | '/notifications/create' | '/repositories/create' + | '/settings/sso-link' | '/volumes/$volumeId' | '/volumes/create' | '/backups/' @@ -254,6 +291,7 @@ export interface FileRouteTypes { | '/settings/' | '/volumes/' | '/repositories/$repositoryId/edit' + | '/settings/sso-link/error' | '/backups/$backupId/' | '/repositories/$repositoryId/' | '/backups/$backupId/$snapshotId/restore' @@ -266,10 +304,12 @@ export interface FileRouteTypes { | '/login' | '/onboarding' | '/api/$' + | '/login/error' | '/backups/create' | '/notifications/$notificationId' | '/notifications/create' | '/repositories/create' + | '/settings/sso-link' | '/volumes/$volumeId' | '/volumes/create' | '/backups' @@ -278,6 +318,7 @@ export interface FileRouteTypes { | '/settings' | '/volumes' | '/repositories/$repositoryId/edit' + | '/settings/sso-link/error' | '/backups/$backupId' | '/repositories/$repositoryId' | '/backups/$backupId/$snapshotId/restore' @@ -286,15 +327,18 @@ export interface FileRouteTypes { id: | '__root__' | '/' + | '/(auth)' | '/(dashboard)' | '/(auth)/download-recovery-key' | '/(auth)/login' | '/(auth)/onboarding' | '/api/$' + | '/(auth)/login/error' | '/(dashboard)/backups/create' | '/(dashboard)/notifications/$notificationId' | '/(dashboard)/notifications/create' | '/(dashboard)/repositories/create' + | '/(dashboard)/settings/sso-link' | '/(dashboard)/volumes/$volumeId' | '/(dashboard)/volumes/create' | '/(dashboard)/backups/' @@ -303,6 +347,7 @@ export interface FileRouteTypes { | '/(dashboard)/settings/' | '/(dashboard)/volumes/' | '/(dashboard)/repositories/$repositoryId/edit' + | '/(dashboard)/settings/sso-link/error' | '/(dashboard)/backups/$backupId/' | '/(dashboard)/repositories/$repositoryId/' | '/(dashboard)/backups/$backupId/$snapshotId/restore' @@ -312,10 +357,8 @@ export interface FileRouteTypes { } export interface RootRouteChildren { IndexRoute: typeof IndexRoute + authRouteRoute: typeof authRouteRouteWithChildren dashboardRouteRoute: typeof dashboardRouteRouteWithChildren - authDownloadRecoveryKeyRoute: typeof authDownloadRecoveryKeyRoute - authLoginRoute: typeof authLoginRoute - authOnboardingRoute: typeof authOnboardingRoute ApiSplatRoute: typeof ApiSplatRoute } @@ -328,6 +371,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof dashboardRouteRouteImport parentRoute: typeof rootRouteImport } + '/(auth)': { + id: '/(auth)' + path: '' + fullPath: '' + preLoaderRoute: typeof authRouteRouteImport + parentRoute: typeof rootRouteImport + } '/': { id: '/' path: '/' @@ -347,21 +397,21 @@ declare module '@tanstack/react-router' { path: '/onboarding' fullPath: '/onboarding' preLoaderRoute: typeof authOnboardingRouteImport - parentRoute: typeof rootRouteImport + parentRoute: typeof authRouteRoute } '/(auth)/login': { id: '/(auth)/login' path: '/login' fullPath: '/login' preLoaderRoute: typeof authLoginRouteImport - parentRoute: typeof rootRouteImport + parentRoute: typeof authRouteRoute } '/(auth)/download-recovery-key': { id: '/(auth)/download-recovery-key' path: '/download-recovery-key' fullPath: '/download-recovery-key' preLoaderRoute: typeof authDownloadRecoveryKeyRouteImport - parentRoute: typeof rootRouteImport + parentRoute: typeof authRouteRoute } '/(dashboard)/volumes/': { id: '/(dashboard)/volumes/' @@ -412,6 +462,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof dashboardVolumesVolumeIdRouteImport parentRoute: typeof dashboardRouteRoute } + '/(dashboard)/settings/sso-link': { + id: '/(dashboard)/settings/sso-link' + path: '/settings/sso-link' + fullPath: '/settings/sso-link' + preLoaderRoute: typeof dashboardSettingsSsoLinkRouteImport + parentRoute: typeof dashboardRouteRoute + } '/(dashboard)/repositories/create': { id: '/(dashboard)/repositories/create' path: '/repositories/create' @@ -440,6 +497,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof dashboardBackupsCreateRouteImport parentRoute: typeof dashboardRouteRoute } + '/(auth)/login/error': { + id: '/(auth)/login/error' + path: '/error' + fullPath: '/login/error' + preLoaderRoute: typeof authLoginErrorRouteImport + parentRoute: typeof authLoginRoute + } '/(dashboard)/repositories/$repositoryId/': { id: '/(dashboard)/repositories/$repositoryId/' path: '/repositories/$repositoryId' @@ -454,6 +518,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof dashboardBackupsBackupIdIndexRouteImport parentRoute: typeof dashboardRouteRoute } + '/(dashboard)/settings/sso-link/error': { + id: '/(dashboard)/settings/sso-link/error' + path: '/error' + fullPath: '/settings/sso-link/error' + preLoaderRoute: typeof dashboardSettingsSsoLinkErrorRouteImport + parentRoute: typeof dashboardSettingsSsoLinkRoute + } '/(dashboard)/repositories/$repositoryId/edit': { id: '/(dashboard)/repositories/$repositoryId/edit' path: '/repositories/$repositoryId/edit' @@ -485,11 +556,54 @@ declare module '@tanstack/react-router' { } } +interface authLoginRouteChildren { + authLoginErrorRoute: typeof authLoginErrorRoute +} + +const authLoginRouteChildren: authLoginRouteChildren = { + authLoginErrorRoute: authLoginErrorRoute, +} + +const authLoginRouteWithChildren = authLoginRoute._addFileChildren( + authLoginRouteChildren, +) + +interface authRouteRouteChildren { + authDownloadRecoveryKeyRoute: typeof authDownloadRecoveryKeyRoute + authLoginRoute: typeof authLoginRouteWithChildren + authOnboardingRoute: typeof authOnboardingRoute +} + +const authRouteRouteChildren: authRouteRouteChildren = { + authDownloadRecoveryKeyRoute: authDownloadRecoveryKeyRoute, + authLoginRoute: authLoginRouteWithChildren, + authOnboardingRoute: authOnboardingRoute, +} + +const authRouteRouteWithChildren = authRouteRoute._addFileChildren( + authRouteRouteChildren, +) + +interface dashboardSettingsSsoLinkRouteChildren { + dashboardSettingsSsoLinkErrorRoute: typeof dashboardSettingsSsoLinkErrorRoute +} + +const dashboardSettingsSsoLinkRouteChildren: dashboardSettingsSsoLinkRouteChildren = + { + dashboardSettingsSsoLinkErrorRoute: dashboardSettingsSsoLinkErrorRoute, + } + +const dashboardSettingsSsoLinkRouteWithChildren = + dashboardSettingsSsoLinkRoute._addFileChildren( + dashboardSettingsSsoLinkRouteChildren, + ) + interface dashboardRouteRouteChildren { dashboardBackupsCreateRoute: typeof dashboardBackupsCreateRoute dashboardNotificationsNotificationIdRoute: typeof dashboardNotificationsNotificationIdRoute dashboardNotificationsCreateRoute: typeof dashboardNotificationsCreateRoute dashboardRepositoriesCreateRoute: typeof dashboardRepositoriesCreateRoute + dashboardSettingsSsoLinkRoute: typeof dashboardSettingsSsoLinkRouteWithChildren dashboardVolumesVolumeIdRoute: typeof dashboardVolumesVolumeIdRoute dashboardVolumesCreateRoute: typeof dashboardVolumesCreateRoute dashboardBackupsIndexRoute: typeof dashboardBackupsIndexRoute @@ -511,6 +625,7 @@ const dashboardRouteRouteChildren: dashboardRouteRouteChildren = { dashboardNotificationsNotificationIdRoute, dashboardNotificationsCreateRoute: dashboardNotificationsCreateRoute, dashboardRepositoriesCreateRoute: dashboardRepositoriesCreateRoute, + dashboardSettingsSsoLinkRoute: dashboardSettingsSsoLinkRouteWithChildren, dashboardVolumesVolumeIdRoute: dashboardVolumesVolumeIdRoute, dashboardVolumesCreateRoute: dashboardVolumesCreateRoute, dashboardBackupsIndexRoute: dashboardBackupsIndexRoute, @@ -537,10 +652,8 @@ const dashboardRouteRouteWithChildren = dashboardRouteRoute._addFileChildren( const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, + authRouteRoute: authRouteRouteWithChildren, dashboardRouteRoute: dashboardRouteRouteWithChildren, - authDownloadRecoveryKeyRoute: authDownloadRecoveryKeyRoute, - authLoginRoute: authLoginRoute, - authOnboardingRoute: authOnboardingRoute, ApiSplatRoute: ApiSplatRoute, } export const routeTree = rootRouteImport diff --git a/app/routes/(auth)/login.error.tsx b/app/routes/(auth)/login.error.tsx new file mode 100644 index 00000000..1ba4f47d --- /dev/null +++ b/app/routes/(auth)/login.error.tsx @@ -0,0 +1,23 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { type } from "arktype"; +import { LoginPage } from "~/client/modules/auth/routes/login"; + +export const Route = createFileRoute("/(auth)/login/error")({ + component: RouteComponent, + validateSearch: type({ error: "string?" }), + head: () => ({ + meta: [ + { title: "Zerobyte - Login Error" }, + { + name: "description", + content: "Resolve SSO sign-in errors.", + }, + ], + }), +}); + +function RouteComponent() { + const { error } = Route.useSearch(); + + return ; +} diff --git a/app/routes/(auth)/login.tsx b/app/routes/(auth)/login.tsx index 0734fab4..2b73cea8 100644 --- a/app/routes/(auth)/login.tsx +++ b/app/routes/(auth)/login.tsx @@ -1,8 +1,10 @@ -import { createFileRoute } from "@tanstack/react-router"; +import { Outlet, createFileRoute, useRouterState } from "@tanstack/react-router"; +import { type } from "arktype"; import { LoginPage } from "~/client/modules/auth/routes/login"; export const Route = createFileRoute("/(auth)/login")({ - component: LoginPage, + component: RouteComponent, + validateSearch: type({ error: "string?" }), head: () => ({ meta: [ { title: "Zerobyte - Login" }, @@ -13,3 +15,16 @@ export const Route = createFileRoute("/(auth)/login")({ ], }), }); + +function RouteComponent() { + const { error } = Route.useSearch(); + const pathname = useRouterState({ + select: (state) => state.location.pathname, + }); + + if (pathname !== "/login") { + return ; + } + + return ; +} diff --git a/app/routes/(auth)/route.tsx b/app/routes/(auth)/route.tsx new file mode 100644 index 00000000..e62aea49 --- /dev/null +++ b/app/routes/(auth)/route.tsx @@ -0,0 +1,9 @@ +import { Outlet, createFileRoute } from "@tanstack/react-router"; +import { authMiddleware } from "~/middleware/auth"; + +export const Route = createFileRoute("/(auth)")({ + component: () => , + server: { + middleware: [authMiddleware], + }, +}); diff --git a/app/routes/(dashboard)/settings/index.tsx b/app/routes/(dashboard)/settings/index.tsx index b76fc716..fa491317 100644 --- a/app/routes/(dashboard)/settings/index.tsx +++ b/app/routes/(dashboard)/settings/index.tsx @@ -3,12 +3,21 @@ import { fetchUser } from "../route"; import type { AppContext } from "~/context"; import { SettingsPage } from "~/client/modules/settings/routes/settings"; import { type } from "arktype"; +import { getAdminUsersOptions, getSsoSettingsOptions } from "~/client/api-client/@tanstack/react-query.gen"; export const Route = createFileRoute("/(dashboard)/settings/")({ component: RouteComponent, validateSearch: type({ tab: "string?" }), - loader: async () => { + loader: async ({ context }) => { const authContext = await fetchUser(); + + if (authContext.user?.role === "admin") { + await Promise.all([ + context.queryClient.ensureQueryData(getSsoSettingsOptions()), + context.queryClient.ensureQueryData(getAdminUsersOptions()), + ]); + } + return authContext as AppContext; }, staticData: { diff --git a/app/routes/(dashboard)/settings/sso-link.error.tsx b/app/routes/(dashboard)/settings/sso-link.error.tsx new file mode 100644 index 00000000..8e10c7c7 --- /dev/null +++ b/app/routes/(dashboard)/settings/sso-link.error.tsx @@ -0,0 +1,10 @@ +import { createFileRoute, redirect } from "@tanstack/react-router"; + +export const Route = createFileRoute("/(dashboard)/settings/sso-link/error")({ + beforeLoad: () => { + throw redirect({ + to: "/settings", + search: () => ({ tab: "users" }), + }); + }, +}); diff --git a/app/routes/(dashboard)/settings/sso-link.tsx b/app/routes/(dashboard)/settings/sso-link.tsx new file mode 100644 index 00000000..5ffd12c8 --- /dev/null +++ b/app/routes/(dashboard)/settings/sso-link.tsx @@ -0,0 +1,10 @@ +import { createFileRoute, redirect } from "@tanstack/react-router"; + +export const Route = createFileRoute("/(dashboard)/settings/sso-link")({ + beforeLoad: () => { + throw redirect({ + to: "/settings", + search: () => ({ tab: "users" }), + }); + }, +}); diff --git a/app/server/db/relations.ts b/app/server/db/relations.ts index 091e6625..e299d02d 100644 --- a/app/server/db/relations.ts +++ b/app/server/db/relations.ts @@ -76,6 +76,7 @@ export const relations = defineRelations(schema, (r) => ({ sessions: r.many.sessionsTable(), members: r.many.member(), twoFactors: r.many.twoFactor(), + ssoProviders: r.many.ssoProvider(), organizations: r.many.organization({ from: r.usersTable.id.through(r.member.userId), to: r.organization.id.through(r.member.organizationId), @@ -104,6 +105,19 @@ export const relations = defineRelations(schema, (r) => ({ volumes: r.many.volumesTable(), members: r.many.member(), invitations: r.many.invitation(), + ssoProviders: r.many.ssoProvider(), + }, + ssoProvider: { + user: r.one.usersTable({ + from: r.ssoProvider.userId, + to: r.usersTable.id, + optional: false, + }), + organization: r.one.organization({ + from: r.ssoProvider.organizationId, + to: r.organization.id, + optional: false, + }), }, volumesTable: { backupSchedules: r.many.backupSchedulesTable(), diff --git a/app/server/db/schema.ts b/app/server/db/schema.ts index 94041fdc..5685340c 100644 --- a/app/server/db/schema.ts +++ b/app/server/db/schema.ts @@ -116,6 +116,7 @@ export const verification = sqliteTable( export type OrganizationMetadata = { resticPassword: string; + passwordLoginEnabled?: boolean; }; export const organization = sqliteTable( @@ -173,6 +174,36 @@ export const invitation = sqliteTable( ], ); +export const ssoProvider = sqliteTable( + "sso_provider", + { + id: text("id").primaryKey(), + providerId: text("provider_id").notNull().unique(), + organizationId: text("organization_id") + .notNull() + .references(() => organization.id, { onDelete: "cascade" }), + userId: text("user_id") + .notNull() + .references(() => usersTable.id, { onDelete: "cascade" }), + issuer: text("issuer").notNull(), + domain: text("domain").notNull(), + oidcConfig: text("oidc_config", { mode: "json" }).$type | null>(), + samlConfig: text("saml_config", { mode: "json" }).$type | null>(), + createdAt: integer("created_at", { mode: "timestamp_ms" }) + .notNull() + .default(sql`(unixepoch() * 1000)`), + updatedAt: integer("updated_at", { mode: "timestamp_ms" }) + .notNull() + .$onUpdate(() => new Date()) + .default(sql`(unixepoch() * 1000)`), + }, + (table) => [ + uniqueIndex("sso_provider_provider_id_uidx").on(table.providerId), + uniqueIndex("sso_provider_organization_id_uidx").on(table.organizationId), + index("sso_provider_domain_idx").on(table.domain), + ], +); + /** * Volumes Table */ diff --git a/app/server/lib/auth.ts b/app/server/lib/auth.ts index ee8f63db..5f47e096 100644 --- a/app/server/lib/auth.ts +++ b/app/server/lib/auth.ts @@ -7,17 +7,17 @@ import { } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { admin, createAuthMiddleware, twoFactor, username, organization } from "better-auth/plugins"; -import { UnauthorizedError } from "http-errors-enhanced"; -import { convertLegacyUserOnFirstLogin } from "./auth-middlewares/convert-legacy-user"; -import { eq } from "drizzle-orm"; +import { sso } from "@better-auth/sso"; import { config } from "../core/config"; import { db } from "../db/db"; import { cryptoUtils } from "../utils/crypto"; -import { organization as organizationTable, member, usersTable } from "../db/schema"; -import { ensureOnlyOneUser } from "./auth-middlewares/only-one-user"; import { authService } from "../modules/auth/auth.service"; import { tanstackStartCookies } from "better-auth/tanstack-start"; import { isValidUsername, normalizeUsername } from "~/lib/username"; +import { ensureOnlyOneUser } from "./auth/middlewares/only-one-user"; +import { convertLegacyUserOnFirstLogin } from "./auth/middlewares/convert-legacy-user"; +import { createUserDefaultOrg } from "./auth/helpers/create-default-org"; +import { isSsoCallbackRequest, requireSsoInvitation } from "./auth/middlewares/require-sso-invitation"; export type AuthMiddlewareContext = MiddlewareContext>; @@ -49,7 +49,13 @@ export const auth = betterAuth({ }, }, create: { - before: async (user) => { + before: async (user, ctx) => { + await requireSsoInvitation(user.email, ctx); + + if (isSsoCallbackRequest(ctx)) { + user.hasDownloadedResticPassword = true; + } + const anyUser = await db.query.usersTable.findFirst(); const isFirstUser = !anyUser; @@ -57,65 +63,19 @@ export const auth = betterAuth({ user.role = "admin"; } - return { data: user }; - }, - after: async (user) => { - const slug = user.email.split("@")[0] + "-" + Math.random().toString(36).slice(-4); - - const resticPassword = cryptoUtils.generateResticPassword(); - const metadata = { - resticPassword: await cryptoUtils.sealSecret(resticPassword), - }; - - try { - db.transaction((tx) => { - const orgId = Bun.randomUUIDv7(); - - tx.insert(organizationTable) - .values({ - name: `${user.name}'s Workspace`, - slug: slug, - id: orgId, - createdAt: new Date(), - metadata, - }) - .run(); - - tx.insert(member) - .values({ - id: Bun.randomUUIDv7(), - userId: user.id, - role: "owner", - organizationId: orgId, - createdAt: new Date(), - }) - .run(); - }); - } catch { - await db.delete(usersTable).where(eq(usersTable.id, user.id)); - - throw new Error(`Failed to create organization for user ${user.id}`); + if (!user.username) { + user.username = Bun.randomUUIDv7(); } + + return { data: user }; }, }, }, session: { create: { - before: async (session) => { - const orgMembership = await db.query.member.findFirst({ - where: { userId: session.userId }, - }); - - if (!orgMembership) { - throw new UnauthorizedError("User does not belong to any organization"); - } - - return { - data: { - ...session, - activeOrganizationId: orgMembership?.organizationId, - }, - }; + before: async (session, ctx) => { + const membership = await createUserDefaultOrg(session.userId, ctx); + return { data: { ...session, activeOrganizationId: membership.organizationId } }; }, }, }, @@ -123,6 +83,11 @@ export const auth = betterAuth({ emailAndPassword: { enabled: true, }, + account: { + accountLinking: { + disableImplicitLinking: true, + }, + }, user: { modelName: "usersTable", additionalFields: { @@ -151,6 +116,13 @@ export const auth = betterAuth({ organization({ allowUserToCreateOrganization: false, }), + sso({ + trustEmailVerified: true, + organizationProvisioning: { + disabled: false, + defaultRole: "member", + }, + }), twoFactor({ backupCodeOptions: { storeBackupCodes: "encrypted", diff --git a/app/server/lib/auth/helpers/__tests__/create-default-org.test.ts b/app/server/lib/auth/helpers/__tests__/create-default-org.test.ts new file mode 100644 index 00000000..acb27a12 --- /dev/null +++ b/app/server/lib/auth/helpers/__tests__/create-default-org.test.ts @@ -0,0 +1,130 @@ +import { beforeEach, describe, expect, test } from "bun:test"; +import type { GenericEndpointContext } from "@better-auth/core"; +import { db } from "~/server/db/db"; +import { account, invitation, member, organization, ssoProvider, usersTable } from "~/server/db/schema"; +import { createUserDefaultOrg } from "../create-default-org"; + +function createMockContext(path: string, params: Record = {}): GenericEndpointContext { + return { + path, + body: {}, + query: {}, + headers: new Headers(), + request: new Request(`http://localhost:3000${path}`), + params, + method: "POST", + context: {} as any, + } as GenericEndpointContext; +} + +function createMockSsoCallbackContext(providerId: string): GenericEndpointContext { + return createMockContext(`/sso/callback/${providerId}`, { providerId }); +} + +function randomId() { + return Bun.randomUUIDv7(); +} + +function randomSlug(prefix: string) { + return `${prefix}-${Math.random().toString(36).slice(2, 8)}`; +} + +async function createUser(email: string, username: string) { + const userId = randomId(); + await db.insert(usersTable).values({ + id: userId, + email, + name: username, + username, + }); + return userId; +} + +describe("createUserDefaultOrg", () => { + beforeEach(async () => { + await db.delete(member); + await db.delete(account); + await db.delete(invitation); + await db.delete(ssoProvider); + await db.delete(organization); + await db.delete(usersTable); + }); + + test("creates invited membership from SSO callback request context", async () => { + const invitedUserId = await createUser("invited@example.com", randomSlug("invited")); + const inviterId = await createUser("inviter@example.com", randomSlug("inviter")); + const organizationId = randomId(); + + await db.insert(organization).values({ + id: organizationId, + name: "Acme", + slug: randomSlug("acme"), + createdAt: new Date(), + }); + + await db.insert(ssoProvider).values({ + id: randomId(), + providerId: "oidc-acme", + organizationId, + userId: inviterId, + issuer: "https://issuer.example.com", + domain: "example.com", + }); + + await db.insert(invitation).values({ + id: randomId(), + organizationId, + email: "Invited@Example.com", + role: "member", + status: "pending", + expiresAt: new Date(Date.now() + 60 * 60 * 1000), + createdAt: new Date(), + inviterId, + }); + + const ctx = createMockSsoCallbackContext("oidc-acme"); + const membership = await createUserDefaultOrg(invitedUserId, ctx); + + expect(membership.organizationId).toBe(organizationId); + expect(membership.role).toBe("member"); + + const updatedInvitation = await db.query.invitation.findFirst({ + where: { organizationId, email: "Invited@Example.com" }, + }); + expect(updatedInvitation?.status).toBe("accepted"); + }); + + test("blocks SSO callback users without pending invitations", async () => { + const userId = await createUser("new-user@example.com", randomSlug("new-user")); + const inviterId = await createUser("inviter@example.com", randomSlug("inviter")); + const organizationId = randomId(); + + await db.insert(organization).values({ + id: organizationId, + name: "Acme", + slug: randomSlug("acme"), + createdAt: new Date(), + }); + + await db.insert(ssoProvider).values({ + id: randomId(), + providerId: "oidc-acme", + organizationId, + userId: inviterId, + issuer: "https://issuer.example.com", + domain: "example.com", + }); + + const ctx = createMockSsoCallbackContext("oidc-acme"); + await expect(createUserDefaultOrg(userId, ctx)).rejects.toThrow("invite-only"); + }); + + test("creates personal workspace for non-SSO flows", async () => { + const userId = await createUser("local-user@example.com", randomSlug("local-user")); + + const membership = await createUserDefaultOrg(userId, null); + + expect(membership.role).toBe("owner"); + expect(membership.organization.name).toContain("Workspace"); + }); +}); diff --git a/app/server/lib/auth/helpers/create-default-org.ts b/app/server/lib/auth/helpers/create-default-org.ts new file mode 100644 index 00000000..1024b85c --- /dev/null +++ b/app/server/lib/auth/helpers/create-default-org.ts @@ -0,0 +1,194 @@ +import { and, eq, gt, inArray } from "drizzle-orm"; +import { UnauthorizedError } from "http-errors-enhanced"; +import type { GenericEndpointContext } from "@better-auth/core"; +import { db } from "~/server/db/db"; +import { invitation, member, organization, ssoProvider } from "~/server/db/schema"; +import { cryptoUtils } from "~/server/utils/crypto"; +import { APIError } from "better-auth"; +import { extractProviderIdFromContext, normalizeEmail } from "../utils/sso-context"; + +async function findMembershipWithOrganization(userId: string, organizationId?: string) { + if (organizationId) { + return db.query.member.findFirst({ + where: { + AND: [{ userId }, { organizationId }], + }, + with: { organization: true }, + }); + } + + return db.query.member.findFirst({ + where: { userId }, + with: { organization: true }, + }); +} + +async function findUserById(userId: string) { + return db.query.usersTable.findFirst({ + where: { id: userId }, + }); +} + +function buildOrgSlug(email: string) { + const [emailPrefix] = email.split("@"); + return `${emailPrefix}-${Math.random().toString(36).slice(-4)}`; +} + +async function getProviderOrganizationIdsFromContext(ctx: GenericEndpointContext | null) { + if (!ctx) { + return []; + } + + const providerId = extractProviderIdFromContext(ctx); + if (!providerId) { + return []; + } + + const provider = await db + .select({ organizationId: ssoProvider.organizationId }) + .from(ssoProvider) + .where(eq(ssoProvider.providerId, providerId)) + .limit(1); + + return provider.map((providerRow) => providerRow.organizationId); +} + +type UserRecord = NonNullable>>; + +async function tryCreateInvitedMembership(userId: string, email: string, ctx: GenericEndpointContext | null) { + let providerOrganizationIds = await getProviderOrganizationIdsFromContext(ctx); + + if (providerOrganizationIds.length === 0) { + const linkedAccounts = await db.query.account.findMany({ + where: { userId }, + }); + + const linkedSsoProviderIds = linkedAccounts + .map((linkedAccount) => linkedAccount.providerId) + .filter((providerId) => providerId !== "credential"); + + if (linkedSsoProviderIds.length === 0) { + return null; + } + + const linkedSsoProviders = await db + .select({ organizationId: ssoProvider.organizationId }) + .from(ssoProvider) + .where(inArray(ssoProvider.providerId, linkedSsoProviderIds)); + + if (linkedSsoProviders.length === 0) { + return null; + } + + providerOrganizationIds = [...new Set(linkedSsoProviders.map((provider) => provider.organizationId))]; + } + + if (providerOrganizationIds.length === 0) { + return null; + } + + const now = new Date(); + const pendingInvitations = await db + .select({ + id: invitation.id, + email: invitation.email, + role: invitation.role, + organizationId: invitation.organizationId, + }) + .from(invitation) + .where( + and( + eq(invitation.status, "pending"), + inArray(invitation.organizationId, providerOrganizationIds), + gt(invitation.expiresAt, now), + ), + ); + + const matchingInvitation = pendingInvitations.find( + (invitationCandidate) => normalizeEmail(invitationCandidate.email) === email, + ); + + if (!matchingInvitation) { + throw new APIError("FORBIDDEN", { + message: "SSO sign-in is invite-only for this organization", + }); + } + + db.transaction((tx) => { + tx.insert(member) + .values({ + id: Bun.randomUUIDv7(), + userId, + role: matchingInvitation.role as "member", + organizationId: matchingInvitation.organizationId, + createdAt: new Date(), + }) + .run(); + + tx.update(invitation).set({ status: "accepted" }).where(eq(invitation.id, matchingInvitation.id)).run(); + }); + + const invitedMembership = await findMembershipWithOrganization(userId, matchingInvitation.organizationId); + + if (!invitedMembership) { + throw new Error("Failed to create invited organization membership"); + } + + return invitedMembership; +} + +async function createDefaultOrganizationMembership(user: UserRecord) { + const resticPassword = cryptoUtils.generateResticPassword(); + const metadata = { resticPassword: await cryptoUtils.sealSecret(resticPassword) }; + + db.transaction((tx) => { + const orgId = Bun.randomUUIDv7(); + const slug = buildOrgSlug(user.email); + + tx.insert(organization) + .values({ + name: `${user.name}'s Workspace`, + slug, + id: orgId, + createdAt: new Date(), + metadata, + }) + .run(); + + tx.insert(member) + .values({ + id: Bun.randomUUIDv7(), + userId: user.id, + role: "owner", + organizationId: orgId, + createdAt: new Date(), + }) + .run(); + }); +} + +export async function createUserDefaultOrg(userId: string, ctx: GenericEndpointContext | null) { + const existingMembership = await findMembershipWithOrganization(userId); + if (existingMembership) { + return existingMembership; + } + + const user = await findUserById(userId); + if (!user) { + throw new UnauthorizedError("User not found"); + } + + const invitedMembership = await tryCreateInvitedMembership(userId, normalizeEmail(user.email), ctx); + if (invitedMembership) { + return invitedMembership; + } + + await createDefaultOrganizationMembership(user); + + const newMembership = await findMembershipWithOrganization(userId); + if (!newMembership) { + throw new Error("Failed to create default organization"); + } + + return newMembership; +} diff --git a/app/server/lib/auth-middlewares/__tests__/convert-legacy-user.test.ts b/app/server/lib/auth/middlewares/__tests__/convert-legacy-user.test.ts similarity index 99% rename from app/server/lib/auth-middlewares/__tests__/convert-legacy-user.test.ts rename to app/server/lib/auth/middlewares/__tests__/convert-legacy-user.test.ts index 0eb75083..d152732e 100644 --- a/app/server/lib/auth-middlewares/__tests__/convert-legacy-user.test.ts +++ b/app/server/lib/auth/middlewares/__tests__/convert-legacy-user.test.ts @@ -2,7 +2,7 @@ import { test, describe, mock, beforeEach, afterEach, expect } from "bun:test"; import { convertLegacyUserOnFirstLogin } from "../convert-legacy-user"; import { db } from "~/server/db/db"; import { usersTable, account, organization, member } from "~/server/db/schema"; -import type { AuthMiddlewareContext } from "../../auth"; +import type { AuthMiddlewareContext } from "~/server/lib/auth"; describe("convertLegacyUserOnFirstLogin", () => { beforeEach(async () => { diff --git a/app/server/lib/auth/middlewares/__tests__/require-sso-invitation.test.ts b/app/server/lib/auth/middlewares/__tests__/require-sso-invitation.test.ts new file mode 100644 index 00000000..b95f6e8e --- /dev/null +++ b/app/server/lib/auth/middlewares/__tests__/require-sso-invitation.test.ts @@ -0,0 +1,124 @@ +import { beforeEach, describe, expect, test } from "bun:test"; +import type { GenericEndpointContext } from "@better-auth/core"; +import { db } from "~/server/db/db"; +import { account, invitation, member, organization, ssoProvider, usersTable } from "~/server/db/schema"; +import { isSsoCallbackRequest, requireSsoInvitation } from "../require-sso-invitation"; + +function createMockContext(path: string, params: Record = {}): GenericEndpointContext { + return { + path, + body: {}, + query: {}, + headers: new Headers(), + request: new Request(`http://test.local${path}`), + params, + method: "POST", + context: {} as any, + } as GenericEndpointContext; +} + +function createMockSsoCallbackContext(providerId: string): GenericEndpointContext { + return createMockContext(`/sso/callback/${providerId}`, { providerId }); +} + +function randomId() { + return Bun.randomUUIDv7(); +} + +function randomSlug(prefix: string) { + return `${prefix}-${Math.random().toString(36).slice(2, 8)}`; +} + +async function createSsoProvider(providerId: string) { + const inviterId = randomId(); + const organizationId = randomId(); + + await db.insert(usersTable).values({ + id: inviterId, + username: randomSlug("inviter"), + email: `${randomSlug("inviter")}@example.com`, + name: "Inviter", + }); + + await db.insert(organization).values({ + id: organizationId, + name: "Acme", + slug: randomSlug("acme"), + createdAt: new Date(), + }); + + await db.insert(ssoProvider).values({ + id: randomId(), + providerId, + organizationId, + userId: inviterId, + issuer: "https://issuer.example.com", + domain: "example.com", + }); + + return { inviterId, organizationId }; +} + +describe("requireSsoInvitation", () => { + beforeEach(async () => { + await db.delete(member); + await db.delete(account); + await db.delete(invitation); + await db.delete(ssoProvider); + await db.delete(organization); + await db.delete(usersTable); + }); + + test("returns early when context is null", async () => { + await createSsoProvider("oidc-acme"); + + expect(requireSsoInvitation("user@example.com", null)).resolves.toBeUndefined(); + }); + + test("returns early when request is not an SSO callback", async () => { + await createSsoProvider("oidc-acme"); + + const ctx = createMockContext("/sign-up/email"); + expect(requireSsoInvitation("user@example.com", ctx)).resolves.toBeUndefined(); + }); + + test("detects whether current request is an SSO callback", async () => { + expect(isSsoCallbackRequest(null)).toBe(false); + + const nonSsoResult = isSsoCallbackRequest(createMockContext("/sign-up/email")); + expect(nonSsoResult).toBe(false); + + const ssoResult = isSsoCallbackRequest(createMockSsoCallbackContext("oidc-acme")); + expect(ssoResult).toBe(true); + }); + + test("blocks SSO callback when no pending invitation exists", async () => { + await createSsoProvider("oidc-acme"); + + const ctx = createMockSsoCallbackContext("oidc-acme"); + expect(requireSsoInvitation("user@example.com", ctx)).rejects.toThrow("must be invited"); + }); + + test("allows SSO callback when a matching pending invitation exists", async () => { + const { inviterId, organizationId } = await createSsoProvider("oidc-acme"); + + await db.insert(invitation).values({ + id: randomId(), + organizationId, + email: "User@Example.com", + role: "member", + status: "pending", + expiresAt: new Date(Date.now() + 60 * 60 * 1000), + createdAt: new Date(), + inviterId, + }); + + const ctx = createMockSsoCallbackContext("oidc-acme"); + expect(requireSsoInvitation("user@example.com", ctx)).resolves.toBeUndefined(); + }); + + test("returns early when provider is not registered", async () => { + const ctx = createMockSsoCallbackContext("missing-provider"); + expect(requireSsoInvitation("user@example.com", ctx)).resolves.toBeUndefined(); + }); +}); diff --git a/app/server/lib/auth-middlewares/convert-legacy-user.ts b/app/server/lib/auth/middlewares/convert-legacy-user.ts similarity index 98% rename from app/server/lib/auth-middlewares/convert-legacy-user.ts rename to app/server/lib/auth/middlewares/convert-legacy-user.ts index 73de8227..1cd2514e 100644 --- a/app/server/lib/auth-middlewares/convert-legacy-user.ts +++ b/app/server/lib/auth/middlewares/convert-legacy-user.ts @@ -2,7 +2,7 @@ import { hashPassword } from "better-auth/crypto"; import { eq } from "drizzle-orm"; import { db } from "~/server/db/db"; import { account, usersTable, member, organization } from "~/server/db/schema"; -import type { AuthMiddlewareContext } from "../auth"; +import type { AuthMiddlewareContext } from "~/server/lib/auth"; import { UnauthorizedError } from "http-errors-enhanced"; import { cryptoUtils } from "~/server/utils/crypto"; import { normalizeUsername } from "~/lib/username"; diff --git a/app/server/lib/auth-middlewares/only-one-user.ts b/app/server/lib/auth/middlewares/only-one-user.ts similarity index 92% rename from app/server/lib/auth-middlewares/only-one-user.ts rename to app/server/lib/auth/middlewares/only-one-user.ts index 67b5bc55..27f11d89 100644 --- a/app/server/lib/auth-middlewares/only-one-user.ts +++ b/app/server/lib/auth/middlewares/only-one-user.ts @@ -1,5 +1,5 @@ import { db } from "~/server/db/db"; -import type { AuthMiddlewareContext } from "../auth"; +import type { AuthMiddlewareContext } from "~/server/lib/auth"; import { logger } from "~/server/utils/logger"; import { ForbiddenError } from "http-errors-enhanced"; import { REGISTRATION_ENABLED_KEY } from "~/server/core/constants"; diff --git a/app/server/lib/auth/middlewares/require-sso-invitation.ts b/app/server/lib/auth/middlewares/require-sso-invitation.ts new file mode 100644 index 00000000..76d2216a --- /dev/null +++ b/app/server/lib/auth/middlewares/require-sso-invitation.ts @@ -0,0 +1,66 @@ +import { and, eq, gt } from "drizzle-orm"; +import { APIError } from "better-auth/api"; +import type { GenericEndpointContext } from "@better-auth/core"; +import { db } from "~/server/db/db"; +import { invitation, ssoProvider } from "~/server/db/schema"; +import { logger } from "~/server/utils/logger"; +import { extractProviderIdFromContext, normalizeEmail } from "../utils/sso-context"; + +export function isSsoCallbackRequest(ctx: GenericEndpointContext | null) { + if (!ctx) { + return false; + } + + return extractProviderIdFromContext(ctx) !== null; +} + +export const requireSsoInvitation = async (userEmail: string, ctx: GenericEndpointContext | null) => { + if (!ctx) { + return; + } + + const providerId = extractProviderIdFromContext(ctx); + if (!providerId) { + return; + } + + const provider = await db + .select({ organizationId: ssoProvider.organizationId }) + .from(ssoProvider) + .where(eq(ssoProvider.providerId, providerId)) + .limit(1); + + if (provider.length === 0) { + return; + } + + const normalizedEmail = normalizeEmail(userEmail); + const now = new Date(); + + logger.debug( + "Checking for pending invitations for email %s in organization %s", + normalizedEmail, + provider[0].organizationId, + ); + + const pendingInvitations = await db + .select({ id: invitation.id, email: invitation.email }) + .from(invitation) + .where( + and( + eq(invitation.organizationId, provider[0].organizationId), + eq(invitation.status, "pending"), + gt(invitation.expiresAt, now), + ), + ); + + const pendingInvitation = pendingInvitations.find( + (invitationCandidate) => normalizeEmail(invitationCandidate.email) === normalizedEmail, + ); + + if (!pendingInvitation) { + throw new APIError("FORBIDDEN", { + message: "Access denied. You must be invited to this organization before you can sign in with SSO.", + }); + } +}; diff --git a/app/server/lib/auth/utils/sso-context.ts b/app/server/lib/auth/utils/sso-context.ts new file mode 100644 index 00000000..41364808 --- /dev/null +++ b/app/server/lib/auth/utils/sso-context.ts @@ -0,0 +1,21 @@ +import type { GenericEndpointContext } from "@better-auth/core"; + +export function normalizeEmail(email: string): string { + return email.trim().toLowerCase(); +} + +export function extractProviderIdFromContext(ctx: GenericEndpointContext): string | null { + if (ctx.params?.providerId) { + return ctx.params.providerId; + } + + if (ctx.request?.url) { + const pathname = new URL(ctx.request.url).pathname; + const ssoCallbackMatch = pathname.match(/\/sso\/(?:saml2\/)?callback\/([^/]+)$/); + if (ssoCallbackMatch) { + return ssoCallbackMatch[1]; + } + } + + return null; +} diff --git a/app/server/lib/functions/organization-context.ts b/app/server/lib/functions/organization-context.ts new file mode 100644 index 00000000..3bd81680 --- /dev/null +++ b/app/server/lib/functions/organization-context.ts @@ -0,0 +1,25 @@ +import { createServerFn } from "@tanstack/react-start"; +import { auth } from "../auth"; +import { getRequest } from "@tanstack/react-start/server"; + +export const getOrganizationContext = createServerFn({ method: "GET" }).handler(async () => { + const request = getRequest(); + + const data = await auth.api.listOrganizations({ + headers: request.headers, + }); + const session = await auth.api.getSession({ headers: request.headers }); + + const activeOrganizationId = session?.session.activeOrganizationId; + const activeOrganization = data.find((org) => org.id === activeOrganizationId); + + const member = await auth.api.getActiveMember({ + headers: request.headers, + }); + + return { + organizations: data, + activeOrganization: activeOrganization || data[0], + activeMember: member, + }; +}); diff --git a/app/server/modules/auth/auth.controller.ts b/app/server/modules/auth/auth.controller.ts index 8d0eb717..562e260d 100644 --- a/app/server/modules/auth/auth.controller.ts +++ b/app/server/modules/auth/auth.controller.ts @@ -1,13 +1,96 @@ import { Hono } from "hono"; -import { type GetStatusDto, getStatusDto, getUserDeletionImpactDto, type UserDeletionImpactDto } from "./auth.dto"; +import { + type GetStatusDto, + getStatusDto, + getUserDeletionImpactDto, + type UserDeletionImpactDto, + getPublicSsoProvidersDto, + type PublicSsoProvidersDto, + getSsoSettingsDto, + type SsoSettingsDto, + getAdminUsersDto, + type AdminUsersDto, + deleteSsoProviderDto, + deleteSsoInvitationDto, +} from "./auth.dto"; import { authService } from "./auth.service"; import { requireAdmin, requireAuth } from "./auth.middleware"; +import { auth } from "~/server/lib/auth"; export const authController = new Hono() .get("/status", getStatusDto, async (c) => { const hasUsers = await authService.hasUsers(); return c.json({ hasUsers }); }) + .get("/sso-providers", getPublicSsoProvidersDto, async (c) => { + const providers = await authService.getPublicSsoProviders(); + return c.json(providers); + }) + .get("/sso-settings", requireAuth, requireAdmin, getSsoSettingsDto, async (c) => { + const headers = c.req.raw.headers; + const activeOrganizationId = c.get("organizationId"); + + if (!activeOrganizationId) { + return c.json({ providers: [], invitations: [] }); + } + + const [providersData, invitationsData] = await Promise.all([ + auth.api.listSSOProviders({ headers }), + auth.api.listInvitations({ + headers, + query: { organizationId: activeOrganizationId }, + }), + ]); + + return c.json({ + providers: providersData.providers.map((provider) => ({ + providerId: provider.providerId, + type: provider.type, + issuer: provider.issuer, + domain: provider.domain, + organizationId: provider.organizationId, + })), + invitations: invitationsData.map((invitation) => ({ + id: invitation.id, + email: invitation.email, + role: invitation.role, + status: invitation.status, + expiresAt: invitation.expiresAt.toISOString(), + })), + }); + }) + .delete("/sso-providers/:providerId", requireAuth, requireAdmin, deleteSsoProviderDto, async (c) => { + const providerId = c.req.param("providerId"); + await authService.deleteSsoProvider(providerId); + + return c.json({ success: true }); + }) + .delete("/sso-invitations/:invitationId", requireAuth, requireAdmin, deleteSsoInvitationDto, async (c) => { + const invitationId = c.req.param("invitationId"); + await authService.deleteSsoInvitation(invitationId); + + return c.json({ success: true }); + }) + .get("/admin-users", requireAuth, requireAdmin, getAdminUsersDto, async (c) => { + const headers = c.req.raw.headers; + + const usersData = await auth.api.listUsers({ + headers, + query: { limit: 100 }, + }); + + return c.json({ + users: usersData.users.map((adminUser) => ({ + id: adminUser.id, + name: adminUser.name, + email: adminUser.email, + role: adminUser.role ?? "user", + banned: Boolean(adminUser.banned), + })), + total: usersData.total, + limit: "limit" in usersData ? (usersData.limit ?? 100) : 100, + }); + }) .get("/deletion-impact/:userId", requireAuth, requireAdmin, getUserDeletionImpactDto, async (c) => { const userId = c.req.param("userId"); const impact = await authService.getUserDeletionImpact(userId); diff --git a/app/server/modules/auth/auth.dto.ts b/app/server/modules/auth/auth.dto.ts index 4a795017..fd0e15a4 100644 --- a/app/server/modules/auth/auth.dto.ts +++ b/app/server/modules/auth/auth.dto.ts @@ -5,6 +5,96 @@ const statusResponseSchema = type({ hasUsers: "boolean", }); +export const publicSsoProvidersDto = type({ + providers: type({ + providerId: "string", + organizationSlug: "string", + }).array(), +}); + +export type PublicSsoProvidersDto = typeof publicSsoProvidersDto.infer; + +export const getPublicSsoProvidersDto = describeRoute({ + description: "Get public SSO providers for the instance", + operationId: "getPublicSsoProviders", + tags: ["Auth"], + responses: { + 200: { + description: "List of public SSO providers", + content: { + "application/json": { + schema: resolver(publicSsoProvidersDto), + }, + }, + }, + }, +}); + +export const ssoSettingsResponse = type({ + providers: type({ + providerId: "string", + type: "string", + issuer: "string", + domain: "string", + organizationId: "string | null", + }).array(), + invitations: type({ + id: "string", + email: "string", + role: "string", + status: "string", + expiresAt: "string", + }).array(), +}); + +export type SsoSettingsDto = typeof ssoSettingsResponse.infer; + +export const getSsoSettingsDto = describeRoute({ + description: "Get SSO providers and invitations for the active organization", + operationId: "getSsoSettings", + tags: ["Auth"], + responses: { + 200: { + description: "SSO settings for the active organization", + content: { + "application/json": { + schema: resolver(ssoSettingsResponse), + }, + }, + }, + }, +}); + +export const adminUsersResponse = type({ + users: type({ + id: "string", + name: "string | null", + email: "string", + role: "string", + banned: "boolean", + }).array(), + total: "number", + limit: "number", +}); + +export type AdminUsersDto = typeof adminUsersResponse.infer; + +export const getAdminUsersDto = describeRoute({ + description: "List admin users for settings management", + operationId: "getAdminUsers", + tags: ["Auth"], + responses: { + 200: { + description: "List of users with roles and status", + content: { + "application/json": { + schema: resolver(adminUsersResponse), + }, + }, + }, + }, +}); + export const getStatusDto = describeRoute({ description: "Get authentication system status", operationId: "getStatus", @@ -52,3 +142,31 @@ export const getUserDeletionImpactDto = describeRoute({ }, }, }); + +export const deleteSsoProviderDto = describeRoute({ + description: "Delete an SSO provider", + operationId: "deleteSsoProvider", + tags: ["Auth"], + responses: { + 200: { + description: "SSO provider deleted successfully", + }, + 403: { + description: "Forbidden", + }, + }, +}); + +export const deleteSsoInvitationDto = describeRoute({ + description: "Delete an SSO invitation", + operationId: "deleteSsoInvitation", + tags: ["Auth"], + responses: { + 200: { + description: "SSO invitation deleted successfully", + }, + 403: { + description: "Forbidden", + }, + }, +}); diff --git a/app/server/modules/auth/auth.service.ts b/app/server/modules/auth/auth.service.ts index cf1bcc22..c2f90211 100644 --- a/app/server/modules/auth/auth.service.ts +++ b/app/server/modules/auth/auth.service.ts @@ -6,9 +6,12 @@ import { volumesTable, repositoriesTable, backupSchedulesTable, + ssoProvider, + account, + invitation, } from "../../db/schema"; import { eq, ne, and, count, inArray } from "drizzle-orm"; -import type { UserDeletionImpactDto } from "./auth.dto"; +import type { PublicSsoProvidersDto, UserDeletionImpactDto } from "./auth.dto"; export class AuthService { /** @@ -19,6 +22,21 @@ export class AuthService { return !!user; } + /** + * Get public SSO providers for the instance + */ + async getPublicSsoProviders(): Promise { + const providers = await db + .select({ + providerId: ssoProvider.providerId, + organizationSlug: organization.slug, + }) + .from(ssoProvider) + .innerJoin(organization, eq(ssoProvider.organizationId, organization.id)); + + return { providers }; + } + /** * Get the impact of deleting a user */ @@ -85,6 +103,23 @@ export class AuthService { await db.delete(organization).where(inArray(organization.id, orgIds)); } } + + /** + * Delete an SSO provider and its associated accounts + */ + async deleteSsoProvider(providerId: string): Promise { + await db.transaction(async (tx) => { + await tx.delete(account).where(eq(account.providerId, providerId)); + await tx.delete(ssoProvider).where(eq(ssoProvider.providerId, providerId)); + }); + } + + /** + * Delete an invitation + */ + async deleteSsoInvitation(invitationId: string): Promise { + await db.delete(invitation).where(eq(invitation.id, invitationId)); + } } export const authService = new AuthService(); diff --git a/bun.lock b/bun.lock index e8035c66..7543c91d 100644 --- a/bun.lock +++ b/bun.lock @@ -5,6 +5,7 @@ "": { "name": "zerobyte", "dependencies": { + "@better-auth/sso": "^1.4.18", "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", @@ -54,6 +55,7 @@ "next-themes": "^0.4.6", "node-cron": "^4.2.1", "qrcode.react": "^4.2.0", + "radix-ui": "^1.4.3", "react": "^19.2.4", "react-dom": "^19.2.4", "react-hook-form": "^7.71.1", @@ -115,6 +117,8 @@ "@ark/util": ["@ark/util@0.56.0", "", {}, "sha512-BghfRC8b9pNs3vBoDJhcta0/c1J1rsoS1+HgVUreMFPdhz/CRAKReAu57YEllNaSy98rWAdY1gE+gFup7OXpgA=="], + "@authenio/xml-encryption": ["@authenio/xml-encryption@2.0.2", "", { "dependencies": { "@xmldom/xmldom": "^0.8.6", "escape-html": "^1.0.3", "xpath": "0.0.32" } }, "sha512-cTlrKttbrRHEw3W+0/I609A2Matj5JQaRvfLtEIGZvlN0RaPi+3ANsMeqAyCAVlH/lUIW2tmtBlSMni74lcXeg=="], + "@azure-rest/core-client": ["@azure-rest/core-client@2.5.1", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-auth": "^1.10.0", "@azure/core-rest-pipeline": "^1.22.0", "@azure/core-tracing": "^1.3.0", "@typespec/ts-http-runtime": "^0.3.0", "tslib": "^2.6.2" } }, "sha512-EHaOXW0RYDKS5CFffnixdyRPak5ytiCtU7uXDcP/uiY+A6jFRwNGzzJBiznkCzvi5EYpY+YWinieqHb0oY916A=="], "@azure/abort-controller": ["@azure/abort-controller@2.1.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA=="], @@ -123,7 +127,7 @@ "@azure/core-client": ["@azure/core-client@1.10.1", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-auth": "^1.10.0", "@azure/core-rest-pipeline": "^1.22.0", "@azure/core-tracing": "^1.3.0", "@azure/core-util": "^1.13.0", "@azure/logger": "^1.3.0", "tslib": "^2.6.2" } }, "sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w=="], - "@azure/core-http-compat": ["@azure/core-http-compat@2.3.1", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-client": "^1.10.0", "@azure/core-rest-pipeline": "^1.22.0" } }, "sha512-az9BkXND3/d5VgdRRQVkiJb2gOmDU8Qcq4GvjtBmDICNiQ9udFmDk4ZpSB5Qq1OmtDJGlQAfBaS4palFsazQ5g=="], + "@azure/core-http-compat": ["@azure/core-http-compat@2.3.2", "", { "dependencies": { "@azure/abort-controller": "^2.1.2" }, "peerDependencies": { "@azure/core-client": "^1.10.0", "@azure/core-rest-pipeline": "^1.22.0" } }, "sha512-Tf6ltdKzOJEgxZeWLCjMxrxbodB/ZeCbzzA1A2qHbhzAjzjHoBVSUeSl/baT/oHAxhc4qdqVaDKnc2+iE932gw=="], "@azure/core-lro": ["@azure/core-lro@2.7.2", "", { "dependencies": { "@azure/abort-controller": "^2.0.0", "@azure/core-util": "^1.2.0", "@azure/logger": "^1.0.0", "tslib": "^2.6.2" } }, "sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw=="], @@ -143,11 +147,11 @@ "@azure/logger": ["@azure/logger@1.3.0", "", { "dependencies": { "@typespec/ts-http-runtime": "^0.3.0", "tslib": "^2.6.2" } }, "sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA=="], - "@azure/msal-browser": ["@azure/msal-browser@4.28.1", "", { "dependencies": { "@azure/msal-common": "15.14.1" } }, "sha512-al2u2fTchbClq3L4C1NlqLm+vwKfhYCPtZN2LR/9xJVaQ4Mnrwf5vANvuyPSJHcGvw50UBmhuVmYUAhTEetTpA=="], + "@azure/msal-browser": ["@azure/msal-browser@4.28.2", "", { "dependencies": { "@azure/msal-common": "15.14.2" } }, "sha512-6vYUMvs6kJxJgxaCmHn/F8VxjLHNh7i9wzfwPGf8kyBJ8Gg2yvBXx175Uev8LdrD1F5C4o7qHa2CC4IrhGE1XQ=="], - "@azure/msal-common": ["@azure/msal-common@15.14.1", "", {}, "sha512-IkzF7Pywt6QKTS0kwdCv/XV8x8JXknZDvSjj/IccooxnP373T5jaadO3FnOrbWo3S0UqkfIDyZNTaQ/oAgRdXw=="], + "@azure/msal-common": ["@azure/msal-common@15.14.2", "", {}, "sha512-n8RBJEUmd5QotoqbZfd+eGBkzuFI1KX6jw2b3WcpSyGjwmzoeI/Jb99opIBPHpb8y312NB+B6+FGi2ZVSR8yfA=="], - "@azure/msal-node": ["@azure/msal-node@3.8.6", "", { "dependencies": { "@azure/msal-common": "15.14.1", "jsonwebtoken": "^9.0.0", "uuid": "^8.3.0" } }, "sha512-XTmhdItcBckcVVTy65Xp+42xG4LX5GK+9AqAsXPXk4IqUNv+LyQo5TMwNjuFYBfAB2GTG9iSQGk+QLc03vhf3w=="], + "@azure/msal-node": ["@azure/msal-node@3.8.7", "", { "dependencies": { "@azure/msal-common": "15.14.2", "jsonwebtoken": "^9.0.0", "uuid": "^8.3.0" } }, "sha512-a+Xnrae+uwLnlw68bplS1X4kuJ9F/7K6afuMFyRkNIskhjgDezl5Fhrx+1pmAlDmC0VaaAxjRQMp1OmcqVwkIg=="], "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], @@ -213,6 +217,8 @@ "@better-auth/core": ["@better-auth/core@1.4.18", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "zod": "^4.3.5" }, "peerDependencies": { "@better-auth/utils": "0.3.0", "@better-fetch/fetch": "1.1.21", "better-call": "1.1.8", "jose": "^6.1.0", "kysely": "^0.28.5", "nanostores": "^1.0.1" } }, "sha512-q+awYgC7nkLEBdx2sW0iJjkzgSHlIxGnOpsN1r/O1+a4m7osJNHtfK2mKJSL1I+GfNyIlxJF8WvD/NLuYMpmcg=="], + "@better-auth/sso": ["@better-auth/sso@1.4.18", "", { "dependencies": { "@better-auth/utils": "0.3.0", "@better-fetch/fetch": "1.1.21", "fast-xml-parser": "^5.2.5", "jose": "^6.1.0", "samlify": "^2.10.1", "zod": "^4.3.5" }, "peerDependencies": { "better-auth": "1.4.18" } }, "sha512-jwTxZUBp71W6YVOavy50DBZ4OFi0a9MGvTTAi+mxMuINFRcz2RyGZv0gb3jy8AJT97TwKU60qRYIWYYyJj1uhA=="], + "@better-auth/telemetry": ["@better-auth/telemetry@1.4.18", "", { "dependencies": { "@better-auth/utils": "0.3.0", "@better-fetch/fetch": "1.1.21" }, "peerDependencies": { "@better-auth/core": "1.4.18" } }, "sha512-e5rDF8S4j3Um/0LIVATL2in9dL4lfO2fr2v1Wio4qTMRbfxqnUDTa+6SZtwdeJrbc4O+a3c+IyIpjG9Q/6GpfQ=="], "@better-auth/utils": ["@better-auth/utils@0.3.0", "", {}, "sha512-W+Adw6ZA6mgvnSnhOki270rwJ42t4XzSK6YWGF//BbVXL6SwCLWfyzBc1lN2m/4RM28KubdBKQ4X5VMoLRNPQw=="], @@ -235,57 +241,57 @@ "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], - "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw=="], + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg=="], - "@esbuild/android-arm": ["@esbuild/android-arm@0.27.2", "", { "os": "android", "cpu": "arm" }, "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA=="], + "@esbuild/android-arm": ["@esbuild/android-arm@0.27.3", "", { "os": "android", "cpu": "arm" }, "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA=="], - "@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.2", "", { "os": "android", "cpu": "arm64" }, "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA=="], + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.3", "", { "os": "android", "cpu": "arm64" }, "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg=="], - "@esbuild/android-x64": ["@esbuild/android-x64@0.27.2", "", { "os": "android", "cpu": "x64" }, "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A=="], + "@esbuild/android-x64": ["@esbuild/android-x64@0.27.3", "", { "os": "android", "cpu": "x64" }, "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ=="], - "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg=="], + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg=="], - "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA=="], + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg=="], - "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g=="], + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w=="], - "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA=="], + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA=="], - "@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.2", "", { "os": "linux", "cpu": "arm" }, "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw=="], + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.3", "", { "os": "linux", "cpu": "arm" }, "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw=="], - "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw=="], + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg=="], - "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w=="], + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.3", "", { "os": "linux", "cpu": "ia32" }, "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg=="], - "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg=="], + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA=="], - "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw=="], + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw=="], - "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ=="], + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA=="], - "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA=="], + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ=="], - "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w=="], + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw=="], - "@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.2", "", { "os": "linux", "cpu": "x64" }, "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA=="], + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.3", "", { "os": "linux", "cpu": "x64" }, "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA=="], - "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw=="], + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA=="], - "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.2", "", { "os": "none", "cpu": "x64" }, "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA=="], + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.3", "", { "os": "none", "cpu": "x64" }, "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA=="], - "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA=="], + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.3", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw=="], - "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg=="], + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.3", "", { "os": "openbsd", "cpu": "x64" }, "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ=="], - "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag=="], + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g=="], - "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg=="], + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.3", "", { "os": "sunos", "cpu": "x64" }, "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA=="], - "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg=="], + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA=="], - "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ=="], + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q=="], - "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.2", "", { "os": "win32", "cpu": "x64" }, "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ=="], + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.3", "", { "os": "win32", "cpu": "x64" }, "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA=="], "@faker-js/faker": ["@faker-js/faker@10.3.0", "", {}, "sha512-It0Sne6P3szg7JIi6CgKbvTZoMjxBZhcv91ZrqrNuaZQfB5WoqYYbzCUOq89YR+VY8juY9M1vDWmDDa2TzfXCw=="], @@ -297,7 +303,7 @@ "@floating-ui/utils": ["@floating-ui/utils@0.2.10", "", {}, "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ=="], - "@happy-dom/global-registrator": ["@happy-dom/global-registrator@20.6.1", "", { "dependencies": { "@types/node": ">=20.0.0", "happy-dom": "^20.6.1" } }, "sha512-4Aji+soqukwUxq2DgHmkjxdGnG7hEiJuprqDlW4Wu6AQ0t8U9ItlICcM5to89pulIsEGrF1CkCoNrufQTcqb8A=="], + "@happy-dom/global-registrator": ["@happy-dom/global-registrator@20.7.0", "", { "dependencies": { "@types/node": ">=20.0.0", "happy-dom": "^20.7.0" } }, "sha512-JdsfSUVeWDP8klYL4y4C4Fae0nAv2V/2W+gHhdiuktyKGZvbSZfJpsk4loakPhTtxt91KHdDroXCCZcFIJrfYQ=="], "@hey-api/codegen-core": ["@hey-api/codegen-core@0.7.0", "", { "dependencies": { "@hey-api/types": "0.1.3", "ansi-colors": "4.1.3", "c12": "3.3.3", "color-support": "1.1.3" }, "peerDependencies": { "typescript": ">=5.5.3" } }, "sha512-HglL4B4QwpzocE+c8qDU6XK8zMf8W8Pcv0RpFDYxHuYALWLTnpDUuEsglC7NQ4vC1maoXsBpMbmwpco0N4QviA=="], @@ -521,55 +527,55 @@ "@oxfmt/binding-win32-x64-msvc": ["@oxfmt/binding-win32-x64-msvc@0.33.0", "", { "os": "win32", "cpu": "x64" }, "sha512-lsBQxbepASwOBUh3chcKAjU+jVAQhLElbPYiagIq26cU8vA9Bttj6t20bMvCQCw31m440IRlNhrK7NpnUI8mzA=="], - "@oxlint-tsgolint/darwin-arm64": ["@oxlint-tsgolint/darwin-arm64@0.14.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-9JdNm9dNeCNgRxBzYb+8vJa/aPD4asc3INdRAC4oJ5EucM2yIPfmHEMlwkAe2WkC7QHPVMG3L9MheAnCrXPTyg=="], + "@oxlint-tsgolint/darwin-arm64": ["@oxlint-tsgolint/darwin-arm64@0.14.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-03WxIXguCXf1pTmoG2C6vqRcbrU9GaJCW6uTIiQdIQq4BrJnVWZv99KEUQQRkuHK78lOLa9g7B4K58NcVcB54g=="], - "@oxlint-tsgolint/darwin-x64": ["@oxlint-tsgolint/darwin-x64@0.14.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-8Z6BkXV7g6BoToCqi/6M7qiDDVHoKzEKRclMXxXiM0JNdk+w4ashNQ101kZh5Xb976vwbo3GuOS8co1UrJ8MQw=="], + "@oxlint-tsgolint/darwin-x64": ["@oxlint-tsgolint/darwin-x64@0.14.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-ksMLl1cIWz3Jw+U79BhyCPdvohZcJ/xAKri5bpT6oeEM2GVnQCHBk/KZKlYrd7hZUTxz0sLnnKHE11XFnLASNQ=="], - "@oxlint-tsgolint/linux-arm64": ["@oxlint-tsgolint/linux-arm64@0.14.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-OZJ/mZSY15cSk3uoqYaKkw5Ue7duaDHfYoigy9bdASeNn4fHnYqeziqOPBvD3K76BDN/mwPLydawsgfY4VPQJQ=="], + "@oxlint-tsgolint/linux-arm64": ["@oxlint-tsgolint/linux-arm64@0.14.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-2BgR535w7GLxBCyQD5DR3dBzbAgiBbG5QX1kAEVzOmWxJhhGxt5lsHdHebRo7ilukYLpBDkerz0mbMErblghCQ=="], - "@oxlint-tsgolint/linux-x64": ["@oxlint-tsgolint/linux-x64@0.14.0", "", { "os": "linux", "cpu": "x64" }, "sha512-NDEBWwtpmCL8AL5jkX9nj9T69QbmaQ5AMSLnMWSJcL4xwR/yh0zk92/662sE2NWiX+8jACycIOa8CzH98rk5gw=="], + "@oxlint-tsgolint/linux-x64": ["@oxlint-tsgolint/linux-x64@0.14.2", "", { "os": "linux", "cpu": "x64" }, "sha512-TUHFyVHfbbGtnTQZbUFgwvv3NzXBgzNLKdMUJw06thpiC7u5OW5qdk4yVXIC/xeVvdl3NAqTfcT4sA32aiMubg=="], - "@oxlint-tsgolint/win32-arm64": ["@oxlint-tsgolint/win32-arm64@0.14.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-onUJNTdoi5eh9HRg0Eb7rBvUtZP8RYP5XCJJkwh1cpNfG8p5JQU0MxYujgdk4ZFGKmg81AsaGAWXDkVNlgMELw=="], + "@oxlint-tsgolint/win32-arm64": ["@oxlint-tsgolint/win32-arm64@0.14.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-OfYHa/irfVggIFEC4TbawsI7Hwrttppv//sO/e00tu4b2QRga7+VHAwtCkSFWSr0+BsO4InRYVA0+pun5BinpQ=="], - "@oxlint-tsgolint/win32-x64": ["@oxlint-tsgolint/win32-x64@0.14.0", "", { "os": "win32", "cpu": "x64" }, "sha512-5pV3fznLN3yZAbEbygZzM9QvcNLYjLmrnM7AYTunhDnkIqagTv5XFwHqXcZf7MZ6oNPtkcImhtzhSpxsk23n3A=="], + "@oxlint-tsgolint/win32-x64": ["@oxlint-tsgolint/win32-x64@0.14.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5gxwbWYE2pP+pzrO4SEeYvLk4N609eAe18rVXUx+en3qtHBkU8VM2jBmMcZdIHn+G05leu4pYvwAvw6tvT9VbA=="], - "@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.48.0", "", { "os": "android", "cpu": "arm" }, "sha512-1Pz/stJvveO9ZO7ll4ZoEY3f6j2FiUgBLBcCRCiW6ylId9L9UKs+gn3X28m3eTnoiFCkhKwmJJ+VO6vwsu7Qtg=="], + "@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.49.0", "", { "os": "android", "cpu": "arm" }, "sha512-2WPoh/2oK9r/i2R4o4J18AOrm3HVlWiHZ8TnuCaS4dX8m5ZzRmHW0I3eLxEurQLHWVruhQN7fHgZnah+ag5iQg=="], - "@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.48.0", "", { "os": "android", "cpu": "arm64" }, "sha512-Zc42RWGE8huo6Ht0lXKjd0NH2lWNmimQHUmD0JFcvShLOuwN+RSEE/kRakc2/0LIgOUuU/R7PaDMCOdQlPgNUQ=="], + "@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.49.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YqJAGvNB11EzoKm1euVhZntb79alhMvWW/j12bYqdvVxn6xzEQWrEDCJg9BPo3A3tBCSUBKH7bVkAiCBqK/L1w=="], - "@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.48.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-jgZs563/4vaG5jH2RSt2TSh8A2jwsFdmhLXrElMdm3Mmto0HPf85FgInLSNi9HcwzQFvkYV8JofcoUg2GH1HTA=="], + "@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.49.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-WFocCRlvVkMhChCJ2qpJfp1Gj/IjvyjuifH9Pex8m8yHonxxQa3d8DZYreuDQU3T4jvSY8rqhoRqnpc61Nlbxw=="], - "@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.48.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-kvo87BujEUjCJREuWDC4aPh1WoXCRFFWE4C7uF6wuoMw2f6N2hypA/cHHcYn9DdL8R2RrgUZPefC8JExyeIMKA=="], + "@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.49.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-BN0KniwvehbUfYztOMwEDkYoojGm/narf5oJf+/ap+6PnzMeWLezMaVARNIS0j3OdMkjHTEP8s3+GdPJ7WDywQ=="], - "@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.48.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-eyzzPaHQKn0RIM+ueDfgfJF2RU//Wp4oaKs2JVoVYcM5HjbCL36+O0S3wO5Xe1NWpcZIG3cEHc/SuOCDRqZDSg=="], + "@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.49.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-SnkAc/DPIY6joMCiP/+53Q+N2UOGMU6ULvbztpmvPJNF/jYPGhNbKtN982uj2Gs6fpbxYkmyj08QnpkD4fbHJA=="], - "@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.48.0", "", { "os": "linux", "cpu": "arm" }, "sha512-p3kSloztK7GRO7FyO3u38UCjZxQTl92VaLDsMQAq0eGoiNmeeEF1KPeE4+Fr+LSkQhF8WvJKSuls6TwOlurdPA=="], + "@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.49.0", "", { "os": "linux", "cpu": "arm" }, "sha512-6Z3EzRvpQVIpO7uFhdiGhdE8Mh3S2VWKLL9xuxVqD6fzPhyI3ugthpYXlCChXzO8FzcYIZ3t1+Kau+h2NY1hqA=="], - "@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.48.0", "", { "os": "linux", "cpu": "arm" }, "sha512-uWM+wiTqLW/V0ZmY/eyTWs8ykhIkzU+K2tz/8m35YepYEzohiUGRbnkpAFXj2ioXpQL+GUe5vmM3SLH6ozlfFw=="], + "@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.49.0", "", { "os": "linux", "cpu": "arm" }, "sha512-wdjXaQYAL/L25732mLlngfst4Jdmi/HLPVHb3yfCoP5mE3lO/pFFrmOJpqWodgv29suWY74Ij+RmJ/YIG5VuzQ=="], - "@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.48.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-OhQNPjs/OICaYqxYJjKKMaIY7p3nJ9IirXcFoHKD+CQE1BZFCeUUAknMzUeLclDCfudH9Vb/UgjFm8+ZM5puAg=="], + "@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.49.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-oSHpm8zmSvAG1BWUumbDRSg7moJbnwoEXKAkwDf/xTQJOzvbUknq95NVQdw/AduZr5dePftalB8rzJNGBogUMg=="], - "@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.48.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-adu5txuwGvQ4C4fjYHJD+vnY+OCwCixBzn7J3KF3iWlVHBBImcosSv+Ye+fbMMJui4HGjifNXzonjKm9pXmOiw=="], + "@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.49.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-xeqkMOARgGBlEg9BQuPDf6ZW711X6BT5qjDyeM5XNowCJeTSdmMhpePJjTEiVbbr3t21sIlK8RE6X5bc04nWyQ=="], - "@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.48.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-inlQQRUnHCny/7b7wA6NjEoJSSZPNea4qnDhWyeqBYWx8ukf2kzNDSiamfhOw6bfAYPm/PVlkVRYaNXQbkLeTQ=="], + "@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.49.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-uvcqRO6PnlJGbL7TeePhTK5+7/JXbxGbN+C6FVmfICDeeRomgQqrfVjf0lUrVpUU8ii8TSkIbNdft3M+oNlOsQ=="], - "@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.48.0", "", { "os": "linux", "cpu": "none" }, "sha512-YiJx6sW6bYebQDZRVWLKm/Drswx/hcjIgbLIhULSn0rRcBKc7d9V6mkqPjKDbhcxJgQD5Zi0yVccJiOdF40AWA=="], + "@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.49.0", "", { "os": "linux", "cpu": "none" }, "sha512-Dw1HkdXAwHNH+ZDserHP2RzXQmhHtpsYYI0hf8fuGAVCIVwvS6w1+InLxpPMY25P8ASRNiFN3hADtoh6lI+4lg=="], - "@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.48.0", "", { "os": "linux", "cpu": "none" }, "sha512-zwSqxMgmb2ITamNfDv9Q9EKBc/4ZhCBP9gkg2hhcgR6sEVGPUDl1AKPC89CBKMxkmPUi3685C38EvqtZn5OtHw=="], + "@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.49.0", "", { "os": "linux", "cpu": "none" }, "sha512-EPlMYaA05tJ9km/0dI9K57iuMq3Tw+nHst7TNIegAJZrBPtsOtYaMFZEaWj02HA8FI5QvSnRHMt+CI+RIhXJBQ=="], - "@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.48.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-c/+2oUWAOsQB5JTem0rW8ODlZllF6pAtGSGXoLSvPTonKI1vAwaKhD9Qw1X36jRbcI3Etkpu/9z/RRjMba8vFQ=="], + "@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.49.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-yZiQL9qEwse34aMbnMb5VqiAWfDY+fLFuoJbHOuzB1OaJZbN1MRF9Nk+W89PIpGr5DNPDipwjZb8+Q7wOywoUQ=="], - "@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.48.0", "", { "os": "linux", "cpu": "x64" }, "sha512-PhauDqeFW5DGed6QxCY5lXZYKSlcBdCXJnH03ZNU6QmDZ0BFM/zSy1oPT2MNb1Afx1G6yOOVk8ErjWsQ7c59ng=="], + "@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.49.0", "", { "os": "linux", "cpu": "x64" }, "sha512-CcCDwMMXSchNkhdgvhVn3DLZ4EnBXAD8o8+gRzahg+IdSt/72y19xBgShJgadIRF0TsRcV/MhDUMwL5N/W54aQ=="], - "@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.48.0", "", { "os": "linux", "cpu": "x64" }, "sha512-6d7LIFFZGiavbHndhf1cK9kG9qmy2Dmr37sV9Ep7j3H+ciFdKSuOzdLh85mEUYMih+b+esMDlF5DU0WQRZPQjw=="], + "@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.49.0", "", { "os": "linux", "cpu": "x64" }, "sha512-u3HfKV8BV6t6UCCbN0RRiyqcymhrnpunVmLFI8sEa5S/EBu+p/0bJ3D7LZ2KT6PsBbrB71SWq4DeFrskOVgIZg=="], - "@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.48.0", "", { "os": "none", "cpu": "arm64" }, "sha512-r+0KK9lK6vFp3tXAgDMOW32o12dxvKS3B9La1uYMGdWAMoSeu2RzG34KmzSpXu6MyLDl4aSVyZLFM8KGdEjwaw=="], + "@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.49.0", "", { "os": "none", "cpu": "arm64" }, "sha512-dRDpH9fw+oeUMpM4br0taYCFpW6jQtOuEIec89rOgDA1YhqwmeRcx0XYeCv7U48p57qJ1XZHeMGM9LdItIjfzA=="], - "@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.48.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-Nkw/MocyT3HSp0OJsKPXrcbxZqSPMTYnLLfsqsoiFKoL1ppVNL65MFa7vuTxJehPlBkjy+95gUgacZtuNMECrg=="], + "@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.49.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-6rrKe/wL9tn0qnOy76i1/0f4Dc3dtQnibGlU4HqR/brVHlVjzLSoaH0gAFnLnznh9yQ6gcFTBFOPrcN/eKPDGA=="], - "@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.48.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-reO1SpefvRmeZSP+WeyWkQd1ArxxDD1MyKgMUKuB8lNuUoxk9QEohYtKnsfsxJuFwMT0JTr7p9wZjouA85GzGQ=="], + "@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.49.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-CXHLWAtLs2xG/aVy1OZiYJzrULlq0QkYpI6cd7VKMrab+qur4fXVE/B1Bp1m0h1qKTj5/FTGg6oU4qaXMjS/ug=="], - "@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.48.0", "", { "os": "win32", "cpu": "x64" }, "sha512-T6zwhfcsrorqAybkOglZdPkTLlEwipbtdO1qjE+flbawvwOMsISoyiuaa7vM7zEyfq1hmDvMq1ndvkYFioranA=="], + "@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.49.0", "", { "os": "win32", "cpu": "x64" }, "sha512-VteIelt78kwzSglOozaQcs6BCS4Lk0j+QA+hGV0W8UeyaqQ3XpbZRhDU55NW1PPvCy1tg4VXsTlEaPovqto7nQ=="], "@playwright/test": ["@playwright/test@1.58.2", "", { "dependencies": { "playwright": "1.58.2" }, "bin": { "playwright": "cli.js" } }, "sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA=="], @@ -577,10 +583,18 @@ "@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="], + "@radix-ui/react-accessible-icon": ["@radix-ui/react-accessible-icon@1.1.7", "", { "dependencies": { "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A=="], + + "@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA=="], + "@radix-ui/react-alert-dialog": ["@radix-ui/react-alert-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw=="], "@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w=="], + "@radix-ui/react-aspect-ratio": ["@radix-ui/react-aspect-ratio@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g=="], + + "@radix-ui/react-avatar": ["@radix-ui/react-avatar@1.1.10", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog=="], + "@radix-ui/react-checkbox": ["@radix-ui/react-checkbox@1.3.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw=="], "@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA=="], @@ -591,22 +605,40 @@ "@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="], + "@radix-ui/react-context-menu": ["@radix-ui/react-context-menu@2.2.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww=="], + "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw=="], "@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="], "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="], + "@radix-ui/react-dropdown-menu": ["@radix-ui/react-dropdown-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw=="], + "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="], "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="], + "@radix-ui/react-form": ["@radix-ui/react-form@0.1.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-label": "2.1.7", "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ=="], + "@radix-ui/react-hover-card": ["@radix-ui/react-hover-card@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg=="], "@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="], "@radix-ui/react-label": ["@radix-ui/react-label@2.1.8", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A=="], + "@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg=="], + + "@radix-ui/react-menubar": ["@radix-ui/react-menubar@1.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA=="], + + "@radix-ui/react-navigation-menu": ["@radix-ui/react-navigation-menu@1.2.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w=="], + + "@radix-ui/react-one-time-password-field": ["@radix-ui/react-one-time-password-field@0.1.8", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg=="], + + "@radix-ui/react-password-toggle-field": ["@radix-ui/react-password-toggle-field@0.1.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-is-hydrated": "0.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw=="], + + "@radix-ui/react-popover": ["@radix-ui/react-popover@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA=="], + "@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.8", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw=="], "@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="], @@ -617,6 +649,8 @@ "@radix-ui/react-progress": ["@radix-ui/react-progress@1.1.8", "", { "dependencies": { "@radix-ui/react-context": "1.1.3", "@radix-ui/react-primitive": "2.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-+gISHcSPUJ7ktBy9RnTqbdKW78bcGke3t6taawyZ71pio1JewwGSJizycs7rLhGTvMJYCQB1DBK4KQsxs7U8dA=="], + "@radix-ui/react-radio-group": ["@radix-ui/react-radio-group@1.3.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ=="], + "@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA=="], "@radix-ui/react-scroll-area": ["@radix-ui/react-scroll-area@1.2.10", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A=="], @@ -625,12 +659,22 @@ "@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.8", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g=="], + "@radix-ui/react-slider": ["@radix-ui/react-slider@1.3.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw=="], + "@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA=="], "@radix-ui/react-switch": ["@radix-ui/react-switch@1.2.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ=="], "@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.13", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A=="], + "@radix-ui/react-toast": ["@radix-ui/react-toast@1.2.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g=="], + + "@radix-ui/react-toggle": ["@radix-ui/react-toggle@1.1.10", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ=="], + + "@radix-ui/react-toggle-group": ["@radix-ui/react-toggle-group@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q=="], + + "@radix-ui/react-toolbar": ["@radix-ui/react-toolbar@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-separator": "1.1.7", "@radix-ui/react-toggle-group": "1.1.11" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg=="], + "@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.2.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg=="], "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="], @@ -641,6 +685,8 @@ "@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g=="], + "@radix-ui/react-use-is-hydrated": ["@radix-ui/react-use-is-hydrated@0.1.0", "", { "dependencies": { "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA=="], + "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="], "@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ=="], @@ -657,63 +703,63 @@ "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.3", "", {}, "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q=="], - "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.57.1", "", { "os": "android", "cpu": "arm" }, "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg=="], + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.58.0", "", { "os": "android", "cpu": "arm" }, "sha512-mr0tmS/4FoVk1cnaeN244A/wjvGDNItZKR8hRhnmCzygyRXYtKF5jVDSIILR1U97CTzAYmbgIj/Dukg62ggG5w=="], - "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.57.1", "", { "os": "android", "cpu": "arm64" }, "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w=="], + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.58.0", "", { "os": "android", "cpu": "arm64" }, "sha512-+s++dbp+/RTte62mQD9wLSbiMTV+xr/PeRJEc/sFZFSBRlHPNPVaf5FXlzAL77Mr8FtSfQqCN+I598M8U41ccQ=="], - "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.57.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg=="], + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.58.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-MFWBwTcYs0jZbINQBXHfSrpSQJq3IUOakcKPzfeSznONop14Pxuqa0Kg19GD0rNBMPQI2tFtu3UzapZpH0Uc1Q=="], - "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.57.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w=="], + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.58.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-yiKJY7pj9c9JwzuKYLFaDZw5gma3fI9bkPEIyofvVfsPqjCWPglSHdpdwXpKGvDeYDms3Qal8qGMEHZ1M/4Udg=="], - "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.57.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug=="], + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.58.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-x97kCoBh5MOevpn/CNK9W1x8BEzO238541BGWBc315uOlN0AD/ifZ1msg+ZQB05Ux+VF6EcYqpiagfLJ8U3LvQ=="], - "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.57.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q=="], + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.58.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Aa8jPoZ6IQAG2eIrcXPpjRcMjROMFxCt1UYPZZtCxRV68WkuSigYtQ/7Zwrcr2IvtNJo7T2JfDXyMLxq5L4Jlg=="], - "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.57.1", "", { "os": "linux", "cpu": "arm" }, "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw=="], + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.58.0", "", { "os": "linux", "cpu": "arm" }, "sha512-Ob8YgT5kD/lSIYW2Rcngs5kNB/44Q2RzBSPz9brf2WEtcGR7/f/E9HeHn1wYaAwKBni+bdXEwgHvUd0x12lQSA=="], - "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.57.1", "", { "os": "linux", "cpu": "arm" }, "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw=="], + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.58.0", "", { "os": "linux", "cpu": "arm" }, "sha512-K+RI5oP1ceqoadvNt1FecL17Qtw/n9BgRSzxif3rTL2QlIu88ccvY+Y9nnHe/cmT5zbH9+bpiJuG1mGHRVwF4Q=="], - "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.57.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g=="], + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.58.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-T+17JAsCKUjmbopcKepJjHWHXSjeW7O5PL7lEFaeQmiVyw4kkc5/lyYKzrv6ElWRX/MrEWfPiJWqbTvfIvjM1Q=="], - "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.57.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q=="], + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.58.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-cCePktb9+6R9itIJdeCFF9txPU7pQeEHB5AbHu/MKsfH/k70ZtOeq1k4YAtBv9Z7mmKI5/wOLYjQ+B9QdxR6LA=="], - "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA=="], + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.58.0", "", { "os": "linux", "cpu": "none" }, "sha512-iekUaLkfliAsDl4/xSdoCJ1gnnIXvoNz85C8U8+ZxknM5pBStfZjeXgB8lXobDQvvPRCN8FPmmuTtH+z95HTmg=="], - "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw=="], + "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.58.0", "", { "os": "linux", "cpu": "none" }, "sha512-68ofRgJNl/jYJbxFjCKE7IwhbfxOl1muPN4KbIqAIe32lm22KmU7E8OPvyy68HTNkI2iV/c8y2kSPSm2mW/Q9Q=="], - "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.57.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w=="], + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.58.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-dpz8vT0i+JqUKuSNPCP5SYyIV2Lh0sNL1+FhM7eLC457d5B9/BC3kDPp5BBftMmTNsBarcPcoz5UGSsnCiw4XQ=="], - "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.57.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw=="], + "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.58.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-4gdkkf9UJ7tafnweBCR/mk4jf3Jfl0cKX9Np80t5i78kjIH0ZdezUv/JDI2VtruE5lunfACqftJ8dIMGN4oHew=="], - "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A=="], + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.58.0", "", { "os": "linux", "cpu": "none" }, "sha512-YFS4vPnOkDTD/JriUeeZurFYoJhPf9GQQEF/v4lltp3mVcBmnsAdjEWhr2cjUCZzZNzxCG0HZOvJU44UGHSdzw=="], - "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw=="], + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.58.0", "", { "os": "linux", "cpu": "none" }, "sha512-x2xgZlFne+QVNKV8b4wwaCS8pwq3y14zedZ5DqLzjdRITvreBk//4Knbcvm7+lWmms9V9qFp60MtUd0/t/PXPw=="], - "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.57.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg=="], + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.58.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-jIhrujyn4UnWF8S+DHSkAkDEO3hLX0cjzxJZPLF80xFyzyUIYgSMRcYQ3+uqEoyDD2beGq7Dj7edi8OnJcS/hg=="], - "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.57.1", "", { "os": "linux", "cpu": "x64" }, "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg=="], + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.58.0", "", { "os": "linux", "cpu": "x64" }, "sha512-+410Srdoh78MKSJxTQ+hZ/Mx+ajd6RjjPwBPNd0R3J9FtL6ZA0GqiiyNjCO9In0IzZkCNrpGymSfn+kgyPQocg=="], - "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.57.1", "", { "os": "linux", "cpu": "x64" }, "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw=="], + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.58.0", "", { "os": "linux", "cpu": "x64" }, "sha512-ZjMyby5SICi227y1MTR3VYBpFTdZs823Rs/hpakufleBoufoOIB6jtm9FEoxn/cgO7l6PM2rCEl5Kre5vX0QrQ=="], - "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.57.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw=="], + "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.58.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-ds4iwfYkSQ0k1nb8LTcyXw//ToHOnNTJtceySpL3fa7tc/AsE+UpUFphW126A6fKBGJD5dhRvg8zw1rvoGFxmw=="], - "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.57.1", "", { "os": "none", "cpu": "arm64" }, "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ=="], + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.58.0", "", { "os": "none", "cpu": "arm64" }, "sha512-fd/zpJniln4ICdPkjWFhZYeY/bpnaN9pGa6ko+5WD38I0tTqk9lXMgXZg09MNdhpARngmxiCg0B0XUamNw/5BQ=="], - "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.57.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ=="], + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.58.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-YpG8dUOip7DCz3nr/JUfPbIUo+2d/dy++5bFzgi4ugOGBIox+qMbbqt/JoORwvI/C9Kn2tz6+Bieoqd5+B1CjA=="], - "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.57.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew=="], + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.58.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-b9DI8jpFQVh4hIXFr0/+N/TzLdpBIoPzjt0Rt4xJbW3mzguV3mduR9cNgiuFcuL/TeORejJhCWiAXe3E/6PxWA=="], - "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.57.1", "", { "os": "win32", "cpu": "x64" }, "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ=="], + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.58.0", "", { "os": "win32", "cpu": "x64" }, "sha512-CSrVpmoRJFN06LL9xhkitkwUcTZtIotYAF5p6XOR2zW0Zz5mzb3IPpcoPhB02frzMHFNo1reQ9xSF5fFm3hUsQ=="], - "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.57.1", "", { "os": "win32", "cpu": "x64" }, "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA=="], + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.58.0", "", { "os": "win32", "cpu": "x64" }, "sha512-QFsBgQNTnh5K0t/sBsjJLq24YVqEIVkGpfN2VHsnN90soZyhaiA9UUHufcctVNL4ypJY0wrwad0wslx2KJQ1/w=="], - "@scalar/core": ["@scalar/core@0.3.38", "", { "dependencies": { "@scalar/types": "0.6.3" } }, "sha512-vacEKCx46szDGKI5x8GrFUQygMMoeOVFxeltkLM1kLylAYs7iLprkwkLlEI0zJezE7mqiWIONh9MDJA2lTciIA=="], + "@scalar/core": ["@scalar/core@0.3.41", "", { "dependencies": { "@scalar/types": "0.6.6" } }, "sha512-IPgiHOSGBDfBcJELbev0lo+ZHc8Q/vA82neX0Ax1iHNGtf/munH+qN5I+p9rGRS60IRQAwABlUo31Y3Gw1c0EA=="], - "@scalar/helpers": ["@scalar/helpers@0.2.12", "", {}, "sha512-Ig/H1Je8nqcDiY+YwFIpATxF2ko7zKrjIZFWK2gGeNTYK4Np9XnqDHg56jM3Xru439Eh4qHq9P/lX7Se5nnxFA=="], + "@scalar/helpers": ["@scalar/helpers@0.2.15", "", {}, "sha512-hMHXejGFVOS4HwCo7C2qddChuvMJs3sEOALo7gNOvwLS4dGLrW8flbSglDki4ttyremlKQstP5WJuPxmHQU3sA=="], - "@scalar/hono-api-reference": ["@scalar/hono-api-reference@0.9.41", "", { "dependencies": { "@scalar/core": "0.3.38" }, "peerDependencies": { "hono": "^4.11.5" } }, "sha512-QPZo3GshWvRU2Y9VRMsl1+FAZv4+Gjud5/Yq6TY/5Xy9Rrez8SMkIgN9cfRjQ5JtU1XqpugtWMBEbiXep4C+Fg=="], + "@scalar/hono-api-reference": ["@scalar/hono-api-reference@0.9.44", "", { "dependencies": { "@scalar/core": "0.3.41" }, "peerDependencies": { "hono": "^4.11.5" } }, "sha512-NusQ3S/LYKmEMOwc5kbKi6Can1b0iHTL/145CxfT5klEXtazhzdiXtYNiPNS99vGYKjub7+oaFR/HXJz4y/w2w=="], - "@scalar/types": ["@scalar/types@0.6.3", "", { "dependencies": { "@scalar/helpers": "0.2.12", "nanoid": "^5.1.6", "type-fest": "^5.3.1", "zod": "^4.3.5" } }, "sha512-uicRSnA29SO+nwywdW5ycjIp24N/6FziPEpgC5nObCy5upUNpArN+xro06T1WX5zFnT9g7ADeTfFkWT+OLk/jA=="], + "@scalar/types": ["@scalar/types@0.6.6", "", { "dependencies": { "@scalar/helpers": "0.2.15", "nanoid": "^5.1.6", "type-fest": "^5.3.1", "zod": "^4.3.5" } }, "sha512-nr3m23p5MnGy4Wb4JFT7aA+jzvYSs/AS40NUEoQMBE1IwtuvG5gtLL0uu6kWpDq4UAfrWGntlAQNX7G8X9D4sg=="], "@standard-community/standard-json": ["@standard-community/standard-json@0.3.5", "", { "peerDependencies": { "@standard-schema/spec": "^1.0.0", "@types/json-schema": "^7.0.15", "@valibot/to-json-schema": "^1.3.0", "arktype": "^2.1.20", "effect": "^3.16.8", "quansync": "^0.2.11", "sury": "^10.0.0", "typebox": "^1.0.17", "valibot": "^1.1.0", "zod": "^3.25.0 || ^4.0.0", "zod-to-json-schema": "^3.24.5" }, "optionalPeers": ["@valibot/to-json-schema", "arktype", "effect", "sury", "typebox", "valibot", "zod", "zod-to-json-schema"] }, "sha512-4+ZPorwDRt47i+O7RjyuaxHRK/37QY/LmgxlGrRrSTLYoFatEOzvqIc85GTlM18SFZ5E91C+v0o/M37wZPpUHA=="], @@ -723,45 +769,45 @@ "@standard-schema/utils": ["@standard-schema/utils@0.3.0", "", {}, "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g=="], - "@tailwindcss/node": ["@tailwindcss/node@4.1.18", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.6.1", "lightningcss": "1.30.2", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.1.18" } }, "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ=="], + "@tailwindcss/node": ["@tailwindcss/node@4.2.0", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.31.1", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.0" } }, "sha512-Yv+fn/o2OmL5fh/Ir62VXItdShnUxfpkMA4Y7jdeC8O81WPB8Kf6TT6GSHvnqgSwDzlB5iT7kDpeXxLsUS0T6Q=="], - "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.18", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.18", "@tailwindcss/oxide-darwin-arm64": "4.1.18", "@tailwindcss/oxide-darwin-x64": "4.1.18", "@tailwindcss/oxide-freebsd-x64": "4.1.18", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18", "@tailwindcss/oxide-linux-arm64-musl": "4.1.18", "@tailwindcss/oxide-linux-x64-gnu": "4.1.18", "@tailwindcss/oxide-linux-x64-musl": "4.1.18", "@tailwindcss/oxide-wasm32-wasi": "4.1.18", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18", "@tailwindcss/oxide-win32-x64-msvc": "4.1.18" } }, "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A=="], + "@tailwindcss/oxide": ["@tailwindcss/oxide@4.2.0", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.2.0", "@tailwindcss/oxide-darwin-arm64": "4.2.0", "@tailwindcss/oxide-darwin-x64": "4.2.0", "@tailwindcss/oxide-freebsd-x64": "4.2.0", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.0", "@tailwindcss/oxide-linux-arm64-gnu": "4.2.0", "@tailwindcss/oxide-linux-arm64-musl": "4.2.0", "@tailwindcss/oxide-linux-x64-gnu": "4.2.0", "@tailwindcss/oxide-linux-x64-musl": "4.2.0", "@tailwindcss/oxide-wasm32-wasi": "4.2.0", "@tailwindcss/oxide-win32-arm64-msvc": "4.2.0", "@tailwindcss/oxide-win32-x64-msvc": "4.2.0" } }, "sha512-AZqQzADaj742oqn2xjl5JbIOzZB/DGCYF/7bpvhA8KvjUj9HJkag6bBuwZvH1ps6dfgxNHyuJVlzSr2VpMgdTQ=="], - "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.18", "", { "os": "android", "cpu": "arm64" }, "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q=="], + "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.2.0", "", { "os": "android", "cpu": "arm64" }, "sha512-F0QkHAVaW/JNBWl4CEKWdZ9PMb0khw5DCELAOnu+RtjAfx5Zgw+gqCHFvqg3AirU1IAd181fwOtJQ5I8Yx5wtw=="], - "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.18", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A=="], + "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.2.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-I0QylkXsBsJMZ4nkUNSR04p6+UptjcwhcVo3Zu828ikiEqHjVmQL9RuQ6uT/cVIiKpvtVA25msu/eRV97JeNSA=="], - "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.18", "", { "os": "darwin", "cpu": "x64" }, "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw=="], + "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.2.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-6TmQIn4p09PBrmnkvbYQ0wbZhLtbaksCDx7Y7R3FYYx0yxNA7xg5KP7dowmQ3d2JVdabIHvs3Hx4K3d5uCf8xg=="], - "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.18", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA=="], + "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.2.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-qBudxDvAa2QwGlq9y7VIzhTvp2mLJ6nD/G8/tI70DCDoneaUeLWBJaPcbfzqRIWraj+o969aDQKvKW9dvkUizw=="], - "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18", "", { "os": "linux", "cpu": "arm" }, "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA=="], + "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.2.0", "", { "os": "linux", "cpu": "arm" }, "sha512-7XKkitpy5NIjFZNUQPeUyNJNJn1CJeV7rmMR+exHfTuOsg8rxIO9eNV5TSEnqRcaOK77zQpsyUkBWmPy8FgdSg=="], - "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.18", "", { "os": "linux", "cpu": "arm64" }, "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw=="], + "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.2.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Mff5a5Q3WoQR01pGU1gr29hHM1N93xYrKkGXfPw/aRtK4bOc331Ho4Tgfsm5WDGvpevqMpdlkCojT3qlCQbCpA=="], - "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.18", "", { "os": "linux", "cpu": "arm64" }, "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg=="], + "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.2.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-XKcSStleEVnbH6W/9DHzZv1YhjE4eSS6zOu2eRtYAIh7aV4o3vIBs+t/B15xlqoxt6ef/0uiqJVB6hkHjWD/0A=="], - "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.18", "", { "os": "linux", "cpu": "x64" }, "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g=="], + "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.2.0", "", { "os": "linux", "cpu": "x64" }, "sha512-/hlXCBqn9K6fi7eAM0RsobHwJYa5V/xzWspVTzxnX+Ft9v6n+30Pz8+RxCn7sQL/vRHHLS30iQPrHQunu6/vJA=="], - "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.18", "", { "os": "linux", "cpu": "x64" }, "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ=="], + "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.2.0", "", { "os": "linux", "cpu": "x64" }, "sha512-lKUaygq4G7sWkhQbfdRRBkaq4LY39IriqBQ+Gk6l5nKq6Ay2M2ZZb1tlIyRNgZKS8cbErTwuYSor0IIULC0SHw=="], - "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.18", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.1.0", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.4.0" }, "cpu": "none" }, "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA=="], + "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.2.0", "", { "dependencies": { "@emnapi/core": "^1.8.1", "@emnapi/runtime": "^1.8.1", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.1.1", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-xuDjhAsFdUuFP5W9Ze4k/o4AskUtI8bcAGU4puTYprr89QaYFmhYOPfP+d1pH+k9ets6RoE23BXZM1X1jJqoyw=="], - "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.18", "", { "os": "win32", "cpu": "arm64" }, "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA=="], + "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.2.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-2UU/15y1sWDEDNJXxEIrfWKC2Yb4YgIW5Xz2fKFqGzFWfoMHWFlfa1EJlGO2Xzjkq/tvSarh9ZTjvbxqWvLLXA=="], - "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.18", "", { "os": "win32", "cpu": "x64" }, "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q=="], + "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.2.0", "", { "os": "win32", "cpu": "x64" }, "sha512-CrFadmFoc+z76EV6LPG1jx6XceDsaCG3lFhyLNo/bV9ByPrE+FnBPckXQVP4XRkN76h3Fjt/a+5Er/oA/nCBvQ=="], "@tailwindcss/typography": ["@tailwindcss/typography@0.5.19", "", { "dependencies": { "postcss-selector-parser": "6.0.10" }, "peerDependencies": { "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" } }, "sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg=="], - "@tailwindcss/vite": ["@tailwindcss/vite@4.1.18", "", { "dependencies": { "@tailwindcss/node": "4.1.18", "@tailwindcss/oxide": "4.1.18", "tailwindcss": "4.1.18" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA=="], + "@tailwindcss/vite": ["@tailwindcss/vite@4.2.0", "", { "dependencies": { "@tailwindcss/node": "4.2.0", "@tailwindcss/oxide": "4.2.0", "tailwindcss": "4.2.0" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-da9mFCaHpoOgtQiWtDGIikTrSpUFBtIZCG3jy/u2BGV+l/X1/pbxzmIUxNt6JWm19N3WtGi4KlJdSH/Si83WOA=="], "@tanstack/history": ["@tanstack/history@1.154.14", "", {}, "sha512-xyIfof8eHBuub1CkBnbKNKQXeRZC4dClhmzePHVOEel4G7lk/dW+TQ16da7CFdeNLv6u6Owf5VoBQxoo6DFTSA=="], - "@tanstack/hotkeys": ["@tanstack/hotkeys@0.1.0", "", { "dependencies": { "@tanstack/store": "^0.8.0" } }, "sha512-2ypLO3C2vKxMbCjiOfA3RzDaUIUYsQtyLc+Qwl6oKzQvWxReGlQN7DOQZSeKyX9D395d3E65e2v7Fm14BzUGew=="], + "@tanstack/hotkeys": ["@tanstack/hotkeys@0.1.3", "", { "dependencies": { "@tanstack/store": "^0.8.0" } }, "sha512-16T+rq9niDG0QcMkG4wIDD2xBCl+dVLEiq5wvNeRpSvndb8jRSATRj1IydipTAA0t0+GT+zdQRTqgXU0Yp54mw=="], "@tanstack/query-core": ["@tanstack/query-core@5.90.20", "", {}, "sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg=="], - "@tanstack/react-hotkeys": ["@tanstack/react-hotkeys@0.1.0", "", { "dependencies": { "@tanstack/hotkeys": "0.1.0", "@tanstack/react-store": "^0.8.0" }, "peerDependencies": { "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-Hteo+hdPKdR2G7uAwTmScu1JUHM/f03lVihxVfR/A3XMyVJmbzi4SJieRk/kLgYKeXFRGIUx/xSI3mHeVc6DbQ=="], + "@tanstack/react-hotkeys": ["@tanstack/react-hotkeys@0.1.3", "", { "dependencies": { "@tanstack/hotkeys": "0.1.3", "@tanstack/react-store": "^0.8.0" }, "peerDependencies": { "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-UnMd2o/MEJB0QtvVVTqUK+6Klp/W3gTqWplg9GyFOpXb7LyHXKp2oyVQDvltezFUl+ugaf3U07ou4hAffcumKQ=="], "@tanstack/react-query": ["@tanstack/react-query@5.90.21", "", { "dependencies": { "@tanstack/query-core": "5.90.20" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-0Lu6y5t+tvlTJMTO7oh5NSpJfpg/5D41LlThfepTixPYkJ0sE2Jj0m0f6yYqujBwIXlId87e234+MxG3D3g7kg=="], @@ -775,7 +821,7 @@ "@tanstack/react-start-server": ["@tanstack/react-start-server@1.161.3", "", { "dependencies": { "@tanstack/history": "1.154.14", "@tanstack/react-router": "1.161.3", "@tanstack/router-core": "1.161.3", "@tanstack/start-client-core": "1.161.3", "@tanstack/start-server-core": "1.161.3" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-5FY3+2LHPPlVkHrrPbhi+TKVl93UCWKC0Ta/hxhXBaYrvBU1uWhIuKgspXT+cWP6XcMPuPrc4qfVWrXHKBMIqg=="], - "@tanstack/react-store": ["@tanstack/react-store@0.8.0", "", { "dependencies": { "@tanstack/store": "0.8.0", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-1vG9beLIuB7q69skxK9r5xiLN3ztzIPfSQSs0GfeqWGO2tGIyInZx0x1COhpx97RKaONSoAb8C3dxacWksm1ow=="], + "@tanstack/react-store": ["@tanstack/react-store@0.8.1", "", { "dependencies": { "@tanstack/store": "0.8.1", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-XItJt+rG8c5Wn/2L/bnxys85rBpm0BfMbhb4zmPVLXAKY9POrp1xd6IbU4PKoOI+jSEGc3vntPRfLGSgXfE2Ig=="], "@tanstack/router-core": ["@tanstack/router-core@1.161.3", "", { "dependencies": { "@tanstack/history": "1.154.14", "@tanstack/store": "^0.9.1", "cookie-es": "^2.0.0", "seroval": "^1.4.2", "seroval-plugins": "^1.4.2", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" } }, "sha512-8EuaGXLUjugQE9Rsb8VrWSy+wImcs/DZ9JORqUJYCmiiWnJzbat8KedQItq/9LCjMJyx4vTLCt8NnZCL+j1Ayg=="], @@ -797,7 +843,7 @@ "@tanstack/start-storage-context": ["@tanstack/start-storage-context@1.161.3", "", { "dependencies": { "@tanstack/router-core": "1.161.3" } }, "sha512-X89oEykLrrhIn+41Q3jXVYRsg9NirM+7Nr0FLajFRle3FpAYggHq6TS8XPRhrv664uLa5Dz225sxCDwC5OT+sQ=="], - "@tanstack/store": ["@tanstack/store@0.8.0", "", {}, "sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ=="], + "@tanstack/store": ["@tanstack/store@0.8.1", "", {}, "sha512-PtOisLjUZPz5VyPRSCGjNOlwTvabdTBQ2K80DpVL1chGVr35WRxfeavAPdNq6pm/t7F8GhoR2qtmkkqtCEtHYw=="], "@tanstack/virtual-file-routes": ["@tanstack/virtual-file-routes@1.154.7", "", {}, "sha512-cHHDnewHozgjpI+MIVp9tcib6lYEQK5MyUr0ChHpHFGBl8Xei55rohFK0I0ve/GKoHeioaK42Smd8OixPp6CTg=="], @@ -859,7 +905,7 @@ "@types/mssql": ["@types/mssql@9.1.9", "", { "dependencies": { "@types/node": "*", "tarn": "^3.0.1", "tedious": "*" } }, "sha512-P0nCgw6vzY23UxZMnbI4N7fnLGANt4LI4yvxze1paPj+LuN28cFv5EI+QidP8udnId/BKhkcRhm/BleNsjK65A=="], - "@types/node": ["@types/node@25.2.3", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ=="], + "@types/node": ["@types/node@25.3.0", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A=="], "@types/react": ["@types/react@19.2.14", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w=="], @@ -877,15 +923,19 @@ "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], - "@typespec/ts-http-runtime": ["@typespec/ts-http-runtime@0.3.2", "", { "dependencies": { "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", "tslib": "^2.6.2" } }, "sha512-IlqQ/Gv22xUC1r/WQm4StLkYQmaaTsXAhUVsNE0+xiyf0yRFiH5++q78U3bw6bLKDCTmh0uqKB9eG9+Bt75Dkg=="], + "@typespec/ts-http-runtime": ["@typespec/ts-http-runtime@0.3.3", "", { "dependencies": { "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", "tslib": "^2.6.2" } }, "sha512-91fp6CAAJSRtH5ja95T1FHSKa8aPW9/Zw6cta81jlZTUw/+Vq8jM/AfF/14h2b71wwR84JUTW/3Y8QPhDAawFA=="], "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], "@vitejs/plugin-react": ["@vitejs/plugin-react@5.1.4", "", { "dependencies": { "@babel/core": "^7.29.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-rc.3", "@types/babel__core": "^7.20.5", "react-refresh": "^0.18.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-VIcFLdRi/VYRU8OL/puL7QXMYafHmqOnwTZY50U1JPlCNj30PxCMx65c494b1K9be9hX83KVt0+gTEwTWLqToA=="], + "@xmldom/is-dom-node": ["@xmldom/is-dom-node@1.0.1", "", {}, "sha512-CJDxIgE5I0FH+ttq/Fxy6nRpxP70+e2O048EPe85J2use3XKdatVM7dDVvFNjQudd9B49NPoZ+8PG49zj4Er8Q=="], + + "@xmldom/xmldom": ["@xmldom/xmldom@0.8.11", "", {}, "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw=="], + "abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="], - "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], + "acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="], "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], @@ -909,6 +959,8 @@ "arktype": ["arktype@2.1.29", "", { "dependencies": { "@ark/schema": "0.56.0", "@ark/util": "0.56.0", "arkregex": "0.0.5" } }, "sha512-jyfKk4xIOzvYNayqnD8ZJQqOwcrTOUbIU4293yrzAjA3O1dWh61j71ArMQ6tS/u4pD7vabSPe7nG3RCyoXW6RQ=="], + "asn1": ["asn1@0.2.6", "", { "dependencies": { "safer-buffer": "~2.1.0" } }, "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ=="], + "ast-types": ["ast-types@0.16.1", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg=="], "babel-dead-code-elimination": ["babel-dead-code-elimination@1.0.12", "", { "dependencies": { "@babel/core": "^7.23.7", "@babel/parser": "^7.23.6", "@babel/traverse": "^7.23.7", "@babel/types": "^7.23.6" } }, "sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig=="], @@ -919,7 +971,7 @@ "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], - "baseline-browser-mapping": ["baseline-browser-mapping@2.9.19", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg=="], + "baseline-browser-mapping": ["baseline-browser-mapping@2.10.0", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA=="], "better-auth": ["better-auth@1.4.18", "", { "dependencies": { "@better-auth/core": "1.4.18", "@better-auth/telemetry": "1.4.18", "@better-auth/utils": "0.3.0", "@better-fetch/fetch": "1.1.21", "@noble/ciphers": "^2.0.0", "@noble/hashes": "^2.0.0", "better-call": "1.1.8", "defu": "^6.1.4", "jose": "^6.1.0", "kysely": "^0.28.5", "nanostores": "^1.0.1", "zod": "^4.3.5" }, "peerDependencies": { "@lynx-js/react": "*", "@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0", "@sveltejs/kit": "^2.0.0", "@tanstack/react-start": "^1.0.0", "@tanstack/solid-start": "^1.0.0", "better-sqlite3": "^12.0.0", "drizzle-kit": ">=0.31.4", "drizzle-orm": ">=0.41.0", "mongodb": "^6.0.0 || ^7.0.0", "mysql2": "^3.0.0", "next": "^14.0.0 || ^15.0.0 || ^16.0.0", "pg": "^8.0.0", "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0", "solid-js": "^1.0.0", "svelte": "^4.0.0 || ^5.0.0", "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0", "vue": "^3.0.0" }, "optionalPeers": ["@lynx-js/react", "@prisma/client", "@sveltejs/kit", "@tanstack/react-start", "@tanstack/solid-start", "better-sqlite3", "drizzle-kit", "drizzle-orm", "mongodb", "mysql2", "next", "pg", "prisma", "react", "react-dom", "solid-js", "svelte", "vitest", "vue"] }, "sha512-bnyifLWBPcYVltH3RhS7CM62MoelEqC6Q+GnZwfiDWNfepXoQZBjEvn4urcERC7NTKgKq5zNBM8rvPvRBa6xcg=="], @@ -945,7 +997,9 @@ "c12": ["c12@3.3.3", "", { "dependencies": { "chokidar": "^5.0.0", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^17.2.3", "exsolve": "^1.0.8", "giget": "^2.0.0", "jiti": "^2.6.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^2.0.0", "pkg-types": "^2.3.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "*" }, "optionalPeers": ["magicast"] }, "sha512-750hTRvgBy5kcMNPdh95Qo+XUBeGo8C7nsKSmedDmaQI+E0r82DwHeM6vBewDe4rGFbnxoa4V9pw+sPh5+Iz8Q=="], - "caniuse-lite": ["caniuse-lite@1.0.30001767", "", {}, "sha512-34+zUAMhSH+r+9eKmYG+k2Rpt8XttfE4yXAjoZvkAPs15xcYQhyBYdalJ65BzivAvGRMViEjy6oKr/S91loekQ=="], + "camelcase": ["camelcase@6.3.0", "", {}, "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="], + + "caniuse-lite": ["caniuse-lite@1.0.30001770", "", {}, "sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw=="], "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], @@ -979,7 +1033,7 @@ "commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="], - "confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], + "confbox": ["confbox@0.2.4", "", {}, "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ=="], "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], @@ -1077,26 +1131,28 @@ "dotenv-expand": ["dotenv-expand@12.0.3", "", { "dependencies": { "dotenv": "^16.4.5" } }, "sha512-uc47g4b+4k/M/SeaW1y4OApx+mtLWl92l5LMPP0GNXctZqELk+YGgOPIIC5elYmUH4OuoK3JLhuRUYegeySiFA=="], - "drizzle-kit": ["drizzle-kit@1.0.0-beta.15-859cf75", "", { "dependencies": { "@drizzle-team/brocli": "^0.11.0", "@js-temporal/polyfill": "^0.5.1", "esbuild": "^0.25.10", "jiti": "^2.6.1" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-Y36s1XQGVb1PgU3aRNgufp1K3D2VkIifu8kv4Ubsmxi+Dq+N7KMklnpp7Knu/XC4FZi2MHPPG3v3o097r0/TcQ=="], + "drizzle-kit": ["drizzle-kit@1.0.0-beta.9-e89174b", "", { "dependencies": { "@drizzle-team/brocli": "^0.11.0", "@js-temporal/polyfill": "^0.5.1", "esbuild": "^0.25.10", "tsx": "^4.20.6" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-Xrw3k8E2CbSZr+kqe3k5W4oxd2fbEyczjKtyGIkAq0x9Wqpa/VtAT6Mkh83sIzqG4OSN7lOoUafsDxSE/AR7RA=="], "drizzle-orm": ["drizzle-orm@1.0.0-beta.9-e89174b", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@effect/sql": "^0.48.5", "@effect/sql-pg": "^0.49.7", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@sqlitecloud/drivers": ">=1.0.653", "@tidbcloud/serverless": "*", "@tursodatabase/database": ">=0.2.1", "@tursodatabase/database-common": ">=0.2.1", "@tursodatabase/database-wasm": ">=0.2.1", "@types/better-sqlite3": "*", "@types/mssql": "^9.1.4", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=9.3.0", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "mssql": "^11.0.1", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@effect/sql", "@effect/sql-pg", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@sqlitecloud/drivers", "@tidbcloud/serverless", "@tursodatabase/database", "@tursodatabase/database-common", "@tursodatabase/database-wasm", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-B5KR/qYMZ0JMOurK+0xi1ObpOQcgrjaC9wHUiU2eTJjLemuh2CoQIw6yur68NxZG6Xcd0b9qghUNC/78/bEfbg=="], "ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="], - "electron-to-chromium": ["electron-to-chromium@1.5.286", "", {}, "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A=="], + "electron-to-chromium": ["electron-to-chromium@1.5.302", "", {}, "sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg=="], "encoding-sniffer": ["encoding-sniffer@0.2.1", "", { "dependencies": { "iconv-lite": "^0.6.3", "whatwg-encoding": "^3.1.1" } }, "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw=="], "enhanced-resolve": ["enhanced-resolve@5.19.0", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg=="], - "entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], + "entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="], "es-toolkit": ["es-toolkit@1.44.0", "", {}, "sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg=="], - "esbuild": ["esbuild@0.27.2", "", { "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" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw=="], + "esbuild": ["esbuild@0.27.3", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.3", "@esbuild/android-arm": "0.27.3", "@esbuild/android-arm64": "0.27.3", "@esbuild/android-x64": "0.27.3", "@esbuild/darwin-arm64": "0.27.3", "@esbuild/darwin-x64": "0.27.3", "@esbuild/freebsd-arm64": "0.27.3", "@esbuild/freebsd-x64": "0.27.3", "@esbuild/linux-arm": "0.27.3", "@esbuild/linux-arm64": "0.27.3", "@esbuild/linux-ia32": "0.27.3", "@esbuild/linux-loong64": "0.27.3", "@esbuild/linux-mips64el": "0.27.3", "@esbuild/linux-ppc64": "0.27.3", "@esbuild/linux-riscv64": "0.27.3", "@esbuild/linux-s390x": "0.27.3", "@esbuild/linux-x64": "0.27.3", "@esbuild/netbsd-arm64": "0.27.3", "@esbuild/netbsd-x64": "0.27.3", "@esbuild/openbsd-arm64": "0.27.3", "@esbuild/openbsd-x64": "0.27.3", "@esbuild/openharmony-arm64": "0.27.3", "@esbuild/sunos-x64": "0.27.3", "@esbuild/win32-arm64": "0.27.3", "@esbuild/win32-ia32": "0.27.3", "@esbuild/win32-x64": "0.27.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg=="], "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], + "escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="], @@ -1119,6 +1175,8 @@ "fast-wrap-ansi": ["fast-wrap-ansi@0.2.0", "", { "dependencies": { "fast-string-width": "^3.0.2" } }, "sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w=="], + "fast-xml-parser": ["fast-xml-parser@5.3.7", "", { "dependencies": { "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-JzVLro9NQv92pOM/jTCR6mHlJh2FGwtomH8ZQjhFj/R29P2Fnj38OgPJVtcvYw6SuKClhgYuwUZf5b3rd8u2mA=="], + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], "fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="], @@ -1133,7 +1191,7 @@ "get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="], - "get-tsconfig": ["get-tsconfig@4.13.1", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-EoY1N2xCn44xU6750Sx7OjOIT59FkmstNc3X6y5xpz7D5cBtZRe/3pSlTkDJgqsOk3WwZPkWfonhhUJfttQo3w=="], + "get-tsconfig": ["get-tsconfig@4.13.6", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw=="], "giget": ["giget@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.6.0", "pathe": "^2.0.3" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA=="], @@ -1143,17 +1201,17 @@ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], - "h3": ["h3@2.0.1-rc.11", "", { "dependencies": { "rou3": "^0.7.12", "srvx": "^0.10.1" }, "peerDependencies": { "crossws": "^0.4.1" }, "optionalPeers": ["crossws"] }, "sha512-2myzjCqy32c1As9TjZW9fNZXtLqNedjFSrdFy2AjFBQQ3LzrnGoDdFDYfC0tV2e4vcyfJ2Sfo/F6NQhO2Ly/Mw=="], + "h3": ["h3@2.0.1-rc.14", "", { "dependencies": { "rou3": "^0.7.12", "srvx": "^0.11.2" }, "peerDependencies": { "crossws": "^0.4.1" }, "optionalPeers": ["crossws"], "bin": { "h3": "bin/h3.mjs" } }, "sha512-163qbGmTr/9rqQRNuqMqtgXnOUAkE4KTdauiC9y0E5iG1I65kte9NyfWvZw5RTDMt6eY+DtyoNzrQ9wA2BfvGQ=="], "h3-v2": ["h3@2.0.1-rc.14", "", { "dependencies": { "rou3": "^0.7.12", "srvx": "^0.11.2" }, "peerDependencies": { "crossws": "^0.4.1" }, "optionalPeers": ["crossws"], "bin": { "h3": "bin/h3.mjs" } }, "sha512-163qbGmTr/9rqQRNuqMqtgXnOUAkE4KTdauiC9y0E5iG1I65kte9NyfWvZw5RTDMt6eY+DtyoNzrQ9wA2BfvGQ=="], - "happy-dom": ["happy-dom@20.6.1", "", { "dependencies": { "@types/node": ">=20.0.0", "@types/whatwg-mimetype": "^3.0.2", "@types/ws": "^8.18.1", "entities": "^6.0.1", "whatwg-mimetype": "^3.0.0", "ws": "^8.18.3" } }, "sha512-+0vhESXXhFwkdjZnJ5DlmJIfUYGgIEEjzIjB+aKJbFuqlvvKyOi+XkI1fYbgYR9QCxG5T08koxsQ6HrQfa5gCQ=="], + "happy-dom": ["happy-dom@20.7.0", "", { "dependencies": { "@types/node": ">=20.0.0", "@types/whatwg-mimetype": "^3.0.2", "@types/ws": "^8.18.1", "entities": "^7.0.1", "whatwg-mimetype": "^3.0.0", "ws": "^8.18.3" } }, "sha512-hR/uLYQdngTyEfxnOoa+e6KTcfBFyc1hgFj/Cc144A5JJUuHFYqIEBDcD4FeGqUeKLRZqJ9eN9u7/GDjYEgS1g=="], "hast-util-to-jsx-runtime": ["hast-util-to-jsx-runtime@2.3.6", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "comma-separated-tokens": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "hast-util-whitespace": "^3.0.0", "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "style-to-js": "^1.0.0", "unist-util-position": "^5.0.0", "vfile-message": "^4.0.0" } }, "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg=="], "hast-util-whitespace": ["hast-util-whitespace@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw=="], - "hono": ["hono@4.11.9", "", {}, "sha512-Eaw2YTGM6WOxA6CXbckaEvslr2Ne4NFsKrvc0v97JD5awbmeBLO5w9Ho9L9kmKonrwF9RJlW6BxT1PVv/agBHQ=="], + "hono": ["hono@4.12.0", "", {}, "sha512-NekXntS5M94pUfiVZ8oXXK/kkri+5WpX2/Ik+LVsl+uvw+soj4roXIsPqO+XsWrAw20mOzaXOZf3Q7PfB9A/IA=="], "hono-openapi": ["hono-openapi@1.2.0", "", { "peerDependencies": { "@hono/standard-validator": "^0.2.0", "@standard-community/standard-json": "^0.3.5", "@standard-community/standard-openapi": "^0.2.9", "@types/json-schema": "^7.0.15", "hono": "^4.8.3", "openapi-types": "^12.1.3" }, "optionalPeers": ["@hono/standard-validator", "hono"] }, "sha512-t3u4v8YCltExDl4d9cLqg/mcrYFSs9Gjb5puF1CePPrvv1JQOo1Kc50HAmGt47CWHIoc/W8Q9LY3t3yqU0dxFw=="], @@ -1207,7 +1265,7 @@ "is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="], - "is-wsl": ["is-wsl@3.1.0", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw=="], + "is-wsl": ["is-wsl@3.1.1", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw=="], "isbot": ["isbot@5.1.35", "", {}, "sha512-waFfC72ZNfwLLuJ2iLaoVaqcNo+CAaLR7xCpAn0Y5WfGzkNHv7ZN39Vbi1y+kb+Zs46XHOX3tZNExroFUPX+Kg=="], @@ -1429,13 +1487,17 @@ "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="], + "node-forge": ["node-forge@1.3.3", "", {}, "sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg=="], + "node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="], + "node-rsa": ["node-rsa@1.1.1", "", { "dependencies": { "asn1": "^0.2.4" } }, "sha512-Jd4cvbJMryN21r5HgxQOpMEqv+ooke/korixNNK3mGqfGJmy0M77WDDzo/05969+OkMy3XW1UuZsSmW9KQm7Fw=="], + "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], - "nypm": ["nypm@0.6.4", "", { "dependencies": { "citty": "^0.2.0", "pathe": "^2.0.3", "tinyexec": "^1.0.2" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-1TvCKjZyyklN+JJj2TS3P4uSQEInrM/HkkuSXsEzm1ApPgBffOn8gFguNnZf07r/1X6vlryfIqMUkJKQMzlZiw=="], + "nypm": ["nypm@0.6.5", "", { "dependencies": { "citty": "^0.2.0", "pathe": "^2.0.3", "tinyexec": "^1.0.2" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-K6AJy1GMVyfyMXRVB88700BJqNUkByijGJM8kEHpLdcAt+vSQAVfkWWHYzuRXHSY6xA2sNc5RjTj0p9rE2izVQ=="], "ofetch": ["ofetch@2.0.0-alpha.3", "", {}, "sha512-zpYTCs2byOuft65vI3z43Dd6iSdFbOZZLb9/d21aCpx2rGastVU9dOCv0lu4ykc1Ur1anAYjDi3SUvR0vq50JA=="], @@ -1451,9 +1513,11 @@ "oxfmt": ["oxfmt@0.33.0", "", { "dependencies": { "tinypool": "2.1.0" }, "optionalDependencies": { "@oxfmt/binding-android-arm-eabi": "0.33.0", "@oxfmt/binding-android-arm64": "0.33.0", "@oxfmt/binding-darwin-arm64": "0.33.0", "@oxfmt/binding-darwin-x64": "0.33.0", "@oxfmt/binding-freebsd-x64": "0.33.0", "@oxfmt/binding-linux-arm-gnueabihf": "0.33.0", "@oxfmt/binding-linux-arm-musleabihf": "0.33.0", "@oxfmt/binding-linux-arm64-gnu": "0.33.0", "@oxfmt/binding-linux-arm64-musl": "0.33.0", "@oxfmt/binding-linux-ppc64-gnu": "0.33.0", "@oxfmt/binding-linux-riscv64-gnu": "0.33.0", "@oxfmt/binding-linux-riscv64-musl": "0.33.0", "@oxfmt/binding-linux-s390x-gnu": "0.33.0", "@oxfmt/binding-linux-x64-gnu": "0.33.0", "@oxfmt/binding-linux-x64-musl": "0.33.0", "@oxfmt/binding-openharmony-arm64": "0.33.0", "@oxfmt/binding-win32-arm64-msvc": "0.33.0", "@oxfmt/binding-win32-ia32-msvc": "0.33.0", "@oxfmt/binding-win32-x64-msvc": "0.33.0" }, "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-ogxBXA9R4BFeo8F1HeMIIxHr5kGnQwKTYZ5k131AEGOq1zLxInNhvYSpyRQ+xIXVMYfCN7yZHKff/lb5lp4auQ=="], - "oxlint": ["oxlint@1.48.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.48.0", "@oxlint/binding-android-arm64": "1.48.0", "@oxlint/binding-darwin-arm64": "1.48.0", "@oxlint/binding-darwin-x64": "1.48.0", "@oxlint/binding-freebsd-x64": "1.48.0", "@oxlint/binding-linux-arm-gnueabihf": "1.48.0", "@oxlint/binding-linux-arm-musleabihf": "1.48.0", "@oxlint/binding-linux-arm64-gnu": "1.48.0", "@oxlint/binding-linux-arm64-musl": "1.48.0", "@oxlint/binding-linux-ppc64-gnu": "1.48.0", "@oxlint/binding-linux-riscv64-gnu": "1.48.0", "@oxlint/binding-linux-riscv64-musl": "1.48.0", "@oxlint/binding-linux-s390x-gnu": "1.48.0", "@oxlint/binding-linux-x64-gnu": "1.48.0", "@oxlint/binding-linux-x64-musl": "1.48.0", "@oxlint/binding-openharmony-arm64": "1.48.0", "@oxlint/binding-win32-arm64-msvc": "1.48.0", "@oxlint/binding-win32-ia32-msvc": "1.48.0", "@oxlint/binding-win32-x64-msvc": "1.48.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.12.2" }, "optionalPeers": ["oxlint-tsgolint"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-m5vyVBgPtPhVCJc3xI//8je9lRc8bYuYB4R/1PH3VPGOjA4vjVhkHtyJukdEjYEjwrw4Qf1eIf+pP9xvfhfMow=="], + "oxlint": ["oxlint@1.49.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.49.0", "@oxlint/binding-android-arm64": "1.49.0", "@oxlint/binding-darwin-arm64": "1.49.0", "@oxlint/binding-darwin-x64": "1.49.0", "@oxlint/binding-freebsd-x64": "1.49.0", "@oxlint/binding-linux-arm-gnueabihf": "1.49.0", "@oxlint/binding-linux-arm-musleabihf": "1.49.0", "@oxlint/binding-linux-arm64-gnu": "1.49.0", "@oxlint/binding-linux-arm64-musl": "1.49.0", "@oxlint/binding-linux-ppc64-gnu": "1.49.0", "@oxlint/binding-linux-riscv64-gnu": "1.49.0", "@oxlint/binding-linux-riscv64-musl": "1.49.0", "@oxlint/binding-linux-s390x-gnu": "1.49.0", "@oxlint/binding-linux-x64-gnu": "1.49.0", "@oxlint/binding-linux-x64-musl": "1.49.0", "@oxlint/binding-openharmony-arm64": "1.49.0", "@oxlint/binding-win32-arm64-msvc": "1.49.0", "@oxlint/binding-win32-ia32-msvc": "1.49.0", "@oxlint/binding-win32-x64-msvc": "1.49.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.14.1" }, "optionalPeers": ["oxlint-tsgolint"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-YZffp0gM+63CJoRhHjtjRnwKtAgUnXM6j63YQ++aigji2NVvLGsUlrXo9gJUXZOdcbfShLYtA6RuTu8GZ4lzOQ=="], - "oxlint-tsgolint": ["oxlint-tsgolint@0.14.0", "", { "optionalDependencies": { "@oxlint-tsgolint/darwin-arm64": "0.14.0", "@oxlint-tsgolint/darwin-x64": "0.14.0", "@oxlint-tsgolint/linux-arm64": "0.14.0", "@oxlint-tsgolint/linux-x64": "0.14.0", "@oxlint-tsgolint/win32-arm64": "0.14.0", "@oxlint-tsgolint/win32-x64": "0.14.0" }, "bin": { "tsgolint": "bin/tsgolint.js" } }, "sha512-BUdiXO0vX7npql4hjLjbZvyM1yDL3U2m1DSZ3jBNl/r+IZaammWN0YmkmlMmYaLnVuTH0+8hO/1rQ6cD+YaEqQ=="], + "oxlint-tsgolint": ["oxlint-tsgolint@0.14.2", "", { "optionalDependencies": { "@oxlint-tsgolint/darwin-arm64": "0.14.2", "@oxlint-tsgolint/darwin-x64": "0.14.2", "@oxlint-tsgolint/linux-arm64": "0.14.2", "@oxlint-tsgolint/linux-x64": "0.14.2", "@oxlint-tsgolint/win32-arm64": "0.14.2", "@oxlint-tsgolint/win32-x64": "0.14.2" }, "bin": { "tsgolint": "bin/tsgolint.js" } }, "sha512-XJsFIQwnYJgXFlNDz2MncQMWYxwnfy4BCy73mdiFN/P13gEZrAfBU4Jmz2XXFf9UG0wPILdi7hYa6t0KmKQLhw=="], + + "pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="], "parse-entities": ["parse-entities@4.0.2", "", { "dependencies": { "@types/unist": "^2.0.0", "character-entities-legacy": "^3.0.0", "character-reference-invalid": "^2.0.0", "decode-named-character-reference": "^1.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0", "is-hexadecimal": "^2.0.0" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="], @@ -1499,13 +1563,15 @@ "quansync": ["quansync@0.2.11", "", {}, "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA=="], + "radix-ui": ["radix-ui@1.4.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-accessible-icon": "1.1.7", "@radix-ui/react-accordion": "1.2.12", "@radix-ui/react-alert-dialog": "1.1.15", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-aspect-ratio": "1.1.7", "@radix-ui/react-avatar": "1.1.10", "@radix-ui/react-checkbox": "1.3.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-context-menu": "2.2.16", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-dropdown-menu": "2.1.16", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-form": "0.1.8", "@radix-ui/react-hover-card": "1.1.15", "@radix-ui/react-label": "2.1.7", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-menubar": "1.1.16", "@radix-ui/react-navigation-menu": "1.2.14", "@radix-ui/react-one-time-password-field": "0.1.8", "@radix-ui/react-password-toggle-field": "0.1.3", "@radix-ui/react-popover": "1.1.15", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-progress": "1.1.7", "@radix-ui/react-radio-group": "1.3.8", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-scroll-area": "1.2.10", "@radix-ui/react-select": "2.2.6", "@radix-ui/react-separator": "1.1.7", "@radix-ui/react-slider": "1.3.6", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-switch": "1.2.6", "@radix-ui/react-tabs": "1.1.13", "@radix-ui/react-toast": "1.2.15", "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-toggle-group": "1.1.11", "@radix-ui/react-toolbar": "1.1.11", "@radix-ui/react-tooltip": "1.2.8", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-escape-keydown": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA=="], + "rc9": ["rc9@2.1.2", "", { "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" } }, "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg=="], "react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="], "react-dom": ["react-dom@19.2.4", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.4" } }, "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ=="], - "react-hook-form": ["react-hook-form@7.71.1", "", { "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19" } }, "sha512-9SUJKCGKo8HUSsCO+y0CtqkqI5nNuaDqTxyqPsZPqIwudpj4rCrAz/jZV+jn57bx5gtZKOh3neQu94DXMc+w5w=="], + "react-hook-form": ["react-hook-form@7.71.2", "", { "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19" } }, "sha512-1CHvcDYzuRUNOflt4MOq3ZM46AronNJtQ1S7tnX6YN4y72qhgiUItpacZUAQ0TyWYci3yz1X+rXaSxiuEm86PA=="], "react-is": ["react-is@17.0.2", "", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="], @@ -1547,7 +1613,7 @@ "rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="], - "rollup": ["rollup@4.57.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.57.1", "@rollup/rollup-android-arm64": "4.57.1", "@rollup/rollup-darwin-arm64": "4.57.1", "@rollup/rollup-darwin-x64": "4.57.1", "@rollup/rollup-freebsd-arm64": "4.57.1", "@rollup/rollup-freebsd-x64": "4.57.1", "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", "@rollup/rollup-linux-arm-musleabihf": "4.57.1", "@rollup/rollup-linux-arm64-gnu": "4.57.1", "@rollup/rollup-linux-arm64-musl": "4.57.1", "@rollup/rollup-linux-loong64-gnu": "4.57.1", "@rollup/rollup-linux-loong64-musl": "4.57.1", "@rollup/rollup-linux-ppc64-gnu": "4.57.1", "@rollup/rollup-linux-ppc64-musl": "4.57.1", "@rollup/rollup-linux-riscv64-gnu": "4.57.1", "@rollup/rollup-linux-riscv64-musl": "4.57.1", "@rollup/rollup-linux-s390x-gnu": "4.57.1", "@rollup/rollup-linux-x64-gnu": "4.57.1", "@rollup/rollup-linux-x64-musl": "4.57.1", "@rollup/rollup-openbsd-x64": "4.57.1", "@rollup/rollup-openharmony-arm64": "4.57.1", "@rollup/rollup-win32-arm64-msvc": "4.57.1", "@rollup/rollup-win32-ia32-msvc": "4.57.1", "@rollup/rollup-win32-x64-gnu": "4.57.1", "@rollup/rollup-win32-x64-msvc": "4.57.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A=="], + "rollup": ["rollup@4.58.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.58.0", "@rollup/rollup-android-arm64": "4.58.0", "@rollup/rollup-darwin-arm64": "4.58.0", "@rollup/rollup-darwin-x64": "4.58.0", "@rollup/rollup-freebsd-arm64": "4.58.0", "@rollup/rollup-freebsd-x64": "4.58.0", "@rollup/rollup-linux-arm-gnueabihf": "4.58.0", "@rollup/rollup-linux-arm-musleabihf": "4.58.0", "@rollup/rollup-linux-arm64-gnu": "4.58.0", "@rollup/rollup-linux-arm64-musl": "4.58.0", "@rollup/rollup-linux-loong64-gnu": "4.58.0", "@rollup/rollup-linux-loong64-musl": "4.58.0", "@rollup/rollup-linux-ppc64-gnu": "4.58.0", "@rollup/rollup-linux-ppc64-musl": "4.58.0", "@rollup/rollup-linux-riscv64-gnu": "4.58.0", "@rollup/rollup-linux-riscv64-musl": "4.58.0", "@rollup/rollup-linux-s390x-gnu": "4.58.0", "@rollup/rollup-linux-x64-gnu": "4.58.0", "@rollup/rollup-linux-x64-musl": "4.58.0", "@rollup/rollup-openbsd-x64": "4.58.0", "@rollup/rollup-openharmony-arm64": "4.58.0", "@rollup/rollup-win32-arm64-msvc": "4.58.0", "@rollup/rollup-win32-ia32-msvc": "4.58.0", "@rollup/rollup-win32-x64-gnu": "4.58.0", "@rollup/rollup-win32-x64-msvc": "4.58.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-wbT0mBmWbIvvq8NeEYWWvevvxnOyhKChir47S66WCxw1SXqhw7ssIYejnQEVt7XYQpsj2y8F9PM+Cr3SNEa0gw=="], "rou3": ["rou3@0.7.12", "", {}, "sha512-iFE4hLDuloSWcD7mjdCDhx2bKcIsYbtOTpfH5MHHLSKMOUyjqQXTeZVa289uuwEGEKFoE/BAPbhaU4B774nceg=="], @@ -1557,6 +1623,8 @@ "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + "samlify": ["samlify@2.10.2", "", { "dependencies": { "@authenio/xml-encryption": "^2.0.2", "@xmldom/xmldom": "^0.8.6", "camelcase": "^6.2.0", "node-forge": "^1.3.0", "node-rsa": "^1.1.1", "pako": "^1.0.10", "uuid": "^8.3.2", "xml": "^1.0.1", "xml-crypto": "^6.1.2", "xml-escape": "^1.1.0", "xpath": "^0.0.32" } }, "sha512-y5s1cHwclqwP8h7K2Wj9SfP1q+1S9+jrs5OAegYTLAiuFi7nDvuKqbiXLmUTvYPMpzHcX94wTY2+D604jgTKvA=="], + "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], "semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], @@ -1591,15 +1659,17 @@ "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="], + "strnum": ["strnum@2.1.2", "", {}, "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ=="], + "style-to-js": ["style-to-js@1.1.21", "", { "dependencies": { "style-to-object": "1.0.14" } }, "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ=="], "style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="], "tagged-tag": ["tagged-tag@1.0.0", "", {}, "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng=="], - "tailwind-merge": ["tailwind-merge@3.4.1", "", {}, "sha512-2OA0rFqWOkITEAOFWSBSApYkDeH9t2B3XSJuI4YztKBzK3mX0737A2qtxDZ7xkw9Zfh0bWl+r34sF3HXV+Ig7Q=="], + "tailwind-merge": ["tailwind-merge@3.5.0", "", {}, "sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A=="], - "tailwindcss": ["tailwindcss@4.1.18", "", {}, "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw=="], + "tailwindcss": ["tailwindcss@4.2.0", "", {}, "sha512-yYzTZ4++b7fNYxFfpnberEEKu43w44aqDMNM9MHMmcKuCH7lL8jJ4yJ7LGHv7rSwiqM0nkiobF9I6cLlpS2P7Q=="], "tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="], @@ -1635,15 +1705,15 @@ "tw-animate-css": ["tw-animate-css@1.4.0", "", {}, "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ=="], - "type-fest": ["type-fest@5.4.3", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-AXSAQJu79WGc79/3e9/CR77I/KQgeY1AhNvcShIH4PTcGYyC4xv6H4R4AUOwkPS5799KlVDAu8zExeCrkGquiA=="], + "type-fest": ["type-fest@5.4.4", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-JnTrzGu+zPV3aXIUhnyWJj4z/wigMsdYajGLIYakqyOW1nPllzXEJee0QQbHj+CTIQtXGlAjuK0UY+2xTyjVAw=="], "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], "ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="], - "undici": ["undici@7.20.0", "", {}, "sha512-MJZrkjyd7DeC+uPZh+5/YaMDxFiiEEaDgbUSVMXayofAkDWF1088CDo+2RPg7B1BuS1qf1vgNE7xqwPxE0DuSQ=="], + "undici": ["undici@7.22.0", "", {}, "sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg=="], - "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + "undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="], "unenv": ["unenv@2.0.0-rc.24", "", { "dependencies": { "pathe": "^2.0.3" } }, "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw=="], @@ -1709,8 +1779,16 @@ "wsl-utils": ["wsl-utils@0.3.1", "", { "dependencies": { "is-wsl": "^3.1.0", "powershell-utils": "^0.1.0" } }, "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg=="], + "xml": ["xml@1.0.1", "", {}, "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw=="], + + "xml-crypto": ["xml-crypto@6.1.2", "", { "dependencies": { "@xmldom/is-dom-node": "^1.0.1", "@xmldom/xmldom": "^0.8.10", "xpath": "^0.0.33" } }, "sha512-leBOVQdVi8FvPJrMYoum7Ici9qyxfE4kVi+AkpUoYCSXaQF4IlBm1cneTK9oAxR61LpYxTx7lNcsnBIeRpGW2w=="], + + "xml-escape": ["xml-escape@1.1.0", "", {}, "sha512-B/T4sDK8Z6aUh/qNr7mjKAwwncIljFuUP+DO/D5hloYFj+90O88z8Wf7oSucZTHxBAsC1/CTP4rtx/x1Uf72Mg=="], + "xmlbuilder2": ["xmlbuilder2@4.0.3", "", { "dependencies": { "@oozcitak/dom": "^2.0.2", "@oozcitak/infra": "^2.0.2", "@oozcitak/util": "^10.0.0", "js-yaml": "^4.1.1" } }, "sha512-bx8Q1STctnNaaDymWnkfQLKofs0mGNN7rLLapJlGuV3VlvegD7Ls4ggMjE3aUSWItCCzU0PEv45lI87iSigiCA=="], + "xpath": ["xpath@0.0.32", "", {}, "sha512-rxMJhSIoiO8vXcWvSifKqhvV96GjiD5wYb8/QHdoRyQvraTpp4IEv944nhGausZZ3u7dhQXteZuZbaqfpB7uYw=="], + "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], "yaml": ["yaml@2.8.2", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A=="], @@ -1727,8 +1805,6 @@ "@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "@happy-dom/global-registrator/@types/node": ["@types/node@25.2.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w=="], - "@hey-api/shared/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], "@radix-ui/react-alert-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], @@ -1737,8 +1813,14 @@ "@radix-ui/react-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + "@radix-ui/react-form/@radix-ui/react-label": ["@radix-ui/react-label@2.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ=="], + "@radix-ui/react-label/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="], + "@radix-ui/react-menu/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + + "@radix-ui/react-popover/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + "@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], "@radix-ui/react-progress/@radix-ui/react-context": ["@radix-ui/react-context@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw=="], @@ -1749,14 +1831,14 @@ "@radix-ui/react-separator/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="], + "@radix-ui/react-toolbar/@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="], + "@radix-ui/react-tooltip/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], - "@reduxjs/toolkit/immer": ["immer@11.1.3", "", {}, "sha512-6jQTc5z0KJFtr1UgFpIL3N9XSC3saRaI9PwWtzM2pSqkNGtiNkYY2OSwkOGDK2XcTRcLb1pi/aNkKZz0nxVH4Q=="], + "@reduxjs/toolkit/immer": ["immer@11.1.4", "", {}, "sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw=="], "@scalar/types/nanoid": ["nanoid@5.1.6", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg=="], - "@tailwindcss/node/lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="], - "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="], @@ -1787,80 +1869,52 @@ "@tanstack/start-plugin-core/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "@types/mssql/@types/node": ["@types/node@25.2.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w=="], - - "@types/readable-stream/@types/node": ["@types/node@25.2.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w=="], - - "@types/ws/@types/node": ["@types/node@25.2.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w=="], - "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "bun-types/@types/node": ["@types/node@25.2.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w=="], - - "c12/dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="], - "cheerio/whatwg-mimetype": ["whatwg-mimetype@4.0.0", "", {}, "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg=="], "cross-fetch/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], "dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], - "dotenv-cli/dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="], - "dotenv-expand/dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="], "encoding-sniffer/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], - "h3-v2/srvx": ["srvx@0.11.4", "", { "bin": { "srvx": "bin/srvx.mjs" } }, "sha512-m/2p87bqWZ94xpRN06qNBwh0xq/D0dXajnvPDSHFqrTogxuTWYNP1UHz6Cf+oY7D+NPLY35TJAp4ESIKn0WArQ=="], + "h3/srvx": ["srvx@0.11.7", "", { "bin": { "srvx": "bin/srvx.mjs" } }, "sha512-p9qj9wkv/MqG1VoJpOsqXv1QcaVcYRk7ifsC6i3TEwDXFyugdhJN4J3KzQPZq2IJJ2ZCt7ASOB++85pEK38jRw=="], - "happy-dom/@types/node": ["@types/node@25.2.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w=="], - - "htmlparser2/entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="], - - "jsonwebtoken/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + "h3-v2/srvx": ["srvx@0.11.7", "", { "bin": { "srvx": "bin/srvx.mjs" } }, "sha512-p9qj9wkv/MqG1VoJpOsqXv1QcaVcYRk7ifsC6i3TEwDXFyugdhJN4J3KzQPZq2IJJ2ZCt7ASOB++85pEK38jRw=="], "libsql/detect-libc": ["detect-libc@2.0.2", "", {}, "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw=="], "mssql/commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], - "nypm/citty": ["citty@0.2.0", "", {}, "sha512-8csy5IBFI2ex2hTVpaHN2j+LNE199AgiI7y4dMintrr8i0lQiFn+0AWMZrWdHKIgMOer65f8IThysYhoReqjWA=="], + "nypm/citty": ["citty@0.2.1", "", {}, "sha512-kEV95lFBhQgtogAPlQfJJ0WGVSokvLr/UEoFPiKKOXF7pl98HfUVUD0ejsuTCld/9xH9vogSywZ5KqHzXrZpqg=="], "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], + "parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], + "playwright/fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="], - "recast/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "radix-ui/@radix-ui/react-label": ["@radix-ui/react-label@2.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ=="], - "tedious/@types/node": ["@types/node@25.2.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w=="], + "radix-ui/@radix-ui/react-progress": ["@radix-ui/react-progress@1.1.7", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg=="], + + "radix-ui/@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="], + + "radix-ui/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + + "recast/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], "tedious/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], "whatwg-encoding/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + "xml-crypto/xpath": ["xpath@0.0.33", "", {}, "sha512-NNXnzrkDrAzalLhIUc01jO2mOzXGXh1JwPgkihcLLzw98c0WgYDmmjSh1Kl3wzaxSVWMuA+fe0WTWOBDWCBmNA=="], + "@azure/identity/open/wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="], - "@tailwindcss/node/lightningcss/lightningcss-android-arm64": ["lightningcss-android-arm64@1.30.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="], - - "@tailwindcss/node/lightningcss/lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA=="], - - "@tailwindcss/node/lightningcss/lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ=="], - - "@tailwindcss/node/lightningcss/lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA=="], - - "@tailwindcss/node/lightningcss/lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.2", "", { "os": "linux", "cpu": "arm" }, "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA=="], - - "@tailwindcss/node/lightningcss/lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A=="], - - "@tailwindcss/node/lightningcss/lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA=="], - - "@tailwindcss/node/lightningcss/lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w=="], - - "@tailwindcss/node/lightningcss/lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA=="], - - "@tailwindcss/node/lightningcss/lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ=="], - - "@tailwindcss/node/lightningcss/lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="], - "@tanstack/react-router/@tanstack/react-store/@tanstack/store": ["@tanstack/store@0.9.1", "", {}, "sha512-+qcNkOy0N1qSGsP7omVCW0SDrXtaDcycPqBDE726yryiA5eTDFpjBReaYjghVJwNf1pcPMyzIwTGlYjCSQR0Fg=="], "@tanstack/router-plugin/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], diff --git a/package.json b/package.json index 8de90b03..c830a0d5 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "test:codegen": "playwright codegen localhost:4096" }, "dependencies": { + "@better-auth/sso": "^1.4.18", "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", @@ -75,6 +76,7 @@ "next-themes": "^0.4.6", "node-cron": "^4.2.1", "qrcode.react": "^4.2.0", + "radix-ui": "^1.4.3", "react": "^19.2.4", "react-dom": "^19.2.4", "react-hook-form": "^7.71.1",