From 44c62a9c7e237083910ea9ef9b4401374d8cdc88 Mon Sep 17 00:00:00 2001 From: Nicolas Meienberger Date: Thu, 13 Nov 2025 19:33:51 +0100 Subject: [PATCH] refactor: correct paths for openapi & drizzle --- Dockerfile | 7 +- .../api-client/@tanstack/react-query.gen.ts | 828 ++++++------------ app/{ => client}/api-client/client.gen.ts | 12 +- .../api-client/client/client.gen.ts | 137 ++- app/{ => client}/api-client/client/index.ts | 2 +- .../api-client/client/types.gen.ts | 55 +- .../api-client/client/utils.gen.ts | 199 +---- app/{ => client}/api-client/core/auth.gen.ts | 0 .../api-client/core/bodySerializer.gen.ts | 16 +- .../api-client/core/params.gen.ts | 43 +- .../api-client/core/pathSerializer.gen.ts | 0 .../api-client/core/queryKeySerializer.gen.ts | 111 +++ .../api-client/core/serverSentEvents.gen.ts | 237 +++++ app/{ => client}/api-client/core/types.gen.ts | 19 +- app/client/api-client/core/utils.gen.ts | 137 +++ app/{ => client}/api-client/index.ts | 3 +- app/{ => client}/api-client/sdk.gen.ts | 220 ++--- app/{ => client}/api-client/types.gen.ts | 8 +- app/client/components/ui/badge.tsx | 2 +- .../drizzle}/0000_known_madelyne_pryor.sql | 0 .../drizzle}/0001_far_frank_castle.sql | 0 .../drizzle}/0002_cheerful_randall.sql | 0 .../drizzle}/0003_mature_hellcat.sql | 0 .../drizzle}/0004_wealthy_tomas.sql | 0 .../drizzle}/0005_simple_alice.sql | 0 .../drizzle}/0006_secret_micromacro.sql | 0 .../drizzle}/0007_watery_sersi.sql | 0 .../drizzle}/0008_silent_lady_bullseye.sql | 0 .../drizzle}/0009_little_adam_warlock.sql | 0 .../drizzle}/0010_perfect_proemial_gods.sql | 0 .../drizzle}/meta/0000_snapshot.json | 0 .../drizzle}/meta/0001_snapshot.json | 0 .../drizzle}/meta/0002_snapshot.json | 0 .../drizzle}/meta/0003_snapshot.json | 0 .../drizzle}/meta/0004_snapshot.json | 0 .../drizzle}/meta/0005_snapshot.json | 0 .../drizzle}/meta/0006_snapshot.json | 0 .../drizzle}/meta/0007_snapshot.json | 0 .../drizzle}/meta/0008_snapshot.json | 0 .../drizzle}/meta/0009_snapshot.json | 0 .../drizzle}/meta/0010_snapshot.json | 0 {drizzle => app/drizzle}/meta/_journal.json | 0 app/server/index.ts | 2 +- bun.lock | 161 +++- drizzle.config.ts | 4 +- openapi-ts.config.ts | 2 +- package.json | 3 + 47 files changed, 1294 insertions(+), 914 deletions(-) rename app/{ => client}/api-client/@tanstack/react-query.gen.ts (66%) rename app/{ => client}/api-client/client.gen.ts (57%) rename app/{ => client}/api-client/client/client.gen.ts (53%) rename app/{ => client}/api-client/client/index.ts (89%) rename app/{ => client}/api-client/client/types.gen.ts (80%) rename app/{ => client}/api-client/client/utils.gen.ts (61%) rename app/{ => client}/api-client/core/auth.gen.ts (100%) rename app/{ => client}/api-client/core/bodySerializer.gen.ts (82%) rename app/{ => client}/api-client/core/params.gen.ts (78%) rename app/{ => client}/api-client/core/pathSerializer.gen.ts (100%) create mode 100644 app/client/api-client/core/queryKeySerializer.gen.ts create mode 100644 app/client/api-client/core/serverSentEvents.gen.ts rename app/{ => client}/api-client/core/types.gen.ts (87%) create mode 100644 app/client/api-client/core/utils.gen.ts rename app/{ => client}/api-client/index.ts (69%) rename app/{ => client}/api-client/sdk.gen.ts (78%) rename app/{ => client}/api-client/types.gen.ts (100%) rename {drizzle => app/drizzle}/0000_known_madelyne_pryor.sql (100%) rename {drizzle => app/drizzle}/0001_far_frank_castle.sql (100%) rename {drizzle => app/drizzle}/0002_cheerful_randall.sql (100%) rename {drizzle => app/drizzle}/0003_mature_hellcat.sql (100%) rename {drizzle => app/drizzle}/0004_wealthy_tomas.sql (100%) rename {drizzle => app/drizzle}/0005_simple_alice.sql (100%) rename {drizzle => app/drizzle}/0006_secret_micromacro.sql (100%) rename {drizzle => app/drizzle}/0007_watery_sersi.sql (100%) rename {drizzle => app/drizzle}/0008_silent_lady_bullseye.sql (100%) rename {drizzle => app/drizzle}/0009_little_adam_warlock.sql (100%) rename {drizzle => app/drizzle}/0010_perfect_proemial_gods.sql (100%) rename {drizzle => app/drizzle}/meta/0000_snapshot.json (100%) rename {drizzle => app/drizzle}/meta/0001_snapshot.json (100%) rename {drizzle => app/drizzle}/meta/0002_snapshot.json (100%) rename {drizzle => app/drizzle}/meta/0003_snapshot.json (100%) rename {drizzle => app/drizzle}/meta/0004_snapshot.json (100%) rename {drizzle => app/drizzle}/meta/0005_snapshot.json (100%) rename {drizzle => app/drizzle}/meta/0006_snapshot.json (100%) rename {drizzle => app/drizzle}/meta/0007_snapshot.json (100%) rename {drizzle => app/drizzle}/meta/0008_snapshot.json (100%) rename {drizzle => app/drizzle}/meta/0009_snapshot.json (100%) rename {drizzle => app/drizzle}/meta/0010_snapshot.json (100%) rename {drizzle => app/drizzle}/meta/_journal.json (100%) diff --git a/Dockerfile b/Dockerfile index 909077ac..5c3126fc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -50,7 +50,7 @@ RUN bun install --frozen-lockfile COPY . . -EXPOSE 3000 +EXPOSE 4096 CMD ["bun", "run", "dev"] @@ -62,13 +62,12 @@ FROM oven/bun:${BUN_VERSION} AS builder WORKDIR /app COPY ./package.json ./bun.lock ./ +RUN bun install --frozen-lockfile COPY ./packages/schemas/package.json ./packages/schemas/package.json COPY ./apps/client/package.json ./apps/client/package.json COPY ./apps/server/package.json ./apps/server/package.json -RUN bun install --frozen-lockfile - COPY . . RUN bun run build @@ -86,6 +85,8 @@ COPY --from=builder /app/dist/server ./dist/server COPY --from=builder /app/drizzle ./assets/migrations COPY --from=builder /app/package.json ./ +RUN bun install --production --frozen-lockfile + # Include third-party licenses and attribution COPY ./LICENSES ./LICENSES COPY ./NOTICES.md ./NOTICES.md diff --git a/app/api-client/@tanstack/react-query.gen.ts b/app/client/api-client/@tanstack/react-query.gen.ts similarity index 66% rename from app/api-client/@tanstack/react-query.gen.ts rename to app/client/api-client/@tanstack/react-query.gen.ts index 38a20d7d..8767f0f0 100644 --- a/app/api-client/@tanstack/react-query.gen.ts +++ b/app/client/api-client/@tanstack/react-query.gen.ts @@ -1,109 +1,184 @@ // This file is auto-generated by @hey-api/openapi-ts +import { type DefaultError, queryOptions, type UseMutationOptions } from "@tanstack/react-query"; + +import { client } from "../client.gen"; import { - type Options, - register, + browseFilesystem, + changePassword, + createBackupSchedule, + createRepository, + createVolume, + deleteBackupSchedule, + deleteRepository, + deleteVolume, + doctorRepository, + downloadResticPassword, + getBackupSchedule, + getBackupScheduleForVolume, + getContainersUsingVolume, + getMe, + getRepository, + getSnapshotDetails, + getStatus, + getSystemInfo, + getVolume, + healthCheckVolume, + listBackupSchedules, + listFiles, + listRcloneRemotes, + listRepositories, + listSnapshotFiles, + listSnapshots, + listVolumes, login, logout, - getMe, - getStatus, - changePassword, - listVolumes, - createVolume, - testConnection, - deleteVolume, - getVolume, - updateVolume, - getContainersUsingVolume, mountVolume, - unmountVolume, - healthCheckVolume, - listFiles, - browseFilesystem, - listRepositories, - createRepository, - listRcloneRemotes, - deleteRepository, - getRepository, - listSnapshots, - getSnapshotDetails, - listSnapshotFiles, + type Options, + register, restoreSnapshot, - doctorRepository, - listBackupSchedules, - createBackupSchedule, - deleteBackupSchedule, - getBackupSchedule, - updateBackupSchedule, - getBackupScheduleForVolume, runBackupNow, stopBackup, - getSystemInfo, - downloadResticPassword, + testConnection, + unmountVolume, + updateBackupSchedule, + updateVolume, } from "../sdk.gen"; -import { queryOptions, type UseMutationOptions, type DefaultError } from "@tanstack/react-query"; import type { - RegisterData, - RegisterResponse, + BrowseFilesystemData, + BrowseFilesystemResponse, + ChangePasswordData, + ChangePasswordResponse, + CreateBackupScheduleData, + CreateBackupScheduleResponse, + CreateRepositoryData, + CreateRepositoryResponse, + CreateVolumeData, + CreateVolumeResponse, + DeleteBackupScheduleData, + DeleteBackupScheduleResponse, + DeleteRepositoryData, + DeleteRepositoryResponse, + DeleteVolumeData, + DeleteVolumeResponse, + DoctorRepositoryData, + DoctorRepositoryResponse, + DownloadResticPasswordData, + DownloadResticPasswordResponse, + GetBackupScheduleData, + GetBackupScheduleForVolumeData, + GetBackupScheduleForVolumeResponse, + GetBackupScheduleResponse, + GetContainersUsingVolumeData, + GetContainersUsingVolumeResponse, + GetMeData, + GetMeResponse, + GetRepositoryData, + GetRepositoryResponse, + GetSnapshotDetailsData, + GetSnapshotDetailsResponse, + GetStatusData, + GetStatusResponse, + GetSystemInfoData, + GetSystemInfoResponse, + GetVolumeData, + GetVolumeResponse, + HealthCheckVolumeData, + HealthCheckVolumeResponse, + ListBackupSchedulesData, + ListBackupSchedulesResponse, + ListFilesData, + ListFilesResponse, + ListRcloneRemotesData, + ListRcloneRemotesResponse, + ListRepositoriesData, + ListRepositoriesResponse, + ListSnapshotFilesData, + ListSnapshotFilesResponse, + ListSnapshotsData, + ListSnapshotsResponse, + ListVolumesData, + ListVolumesResponse, LoginData, LoginResponse, LogoutData, LogoutResponse, - GetMeData, - GetStatusData, - ChangePasswordData, - ChangePasswordResponse, - ListVolumesData, - CreateVolumeData, - CreateVolumeResponse, - TestConnectionData, - TestConnectionResponse, - DeleteVolumeData, - DeleteVolumeResponse, - GetVolumeData, - UpdateVolumeData, - UpdateVolumeResponse, - GetContainersUsingVolumeData, MountVolumeData, MountVolumeResponse, - UnmountVolumeData, - UnmountVolumeResponse, - HealthCheckVolumeData, - HealthCheckVolumeResponse, - ListFilesData, - BrowseFilesystemData, - ListRepositoriesData, - CreateRepositoryData, - CreateRepositoryResponse, - ListRcloneRemotesData, - DeleteRepositoryData, - DeleteRepositoryResponse, - GetRepositoryData, - ListSnapshotsData, - GetSnapshotDetailsData, - ListSnapshotFilesData, + RegisterData, + RegisterResponse, RestoreSnapshotData, RestoreSnapshotResponse, - DoctorRepositoryData, - DoctorRepositoryResponse, - ListBackupSchedulesData, - CreateBackupScheduleData, - CreateBackupScheduleResponse, - DeleteBackupScheduleData, - DeleteBackupScheduleResponse, - GetBackupScheduleData, - UpdateBackupScheduleData, - UpdateBackupScheduleResponse, - GetBackupScheduleForVolumeData, RunBackupNowData, RunBackupNowResponse, StopBackupData, StopBackupResponse, - GetSystemInfoData, - DownloadResticPasswordData, - DownloadResticPasswordResponse, + TestConnectionData, + TestConnectionResponse, + UnmountVolumeData, + UnmountVolumeResponse, + UpdateBackupScheduleData, + UpdateBackupScheduleResponse, + UpdateVolumeData, + UpdateVolumeResponse, } from "../types.gen"; -import { client as _heyApiClient } from "../client.gen"; + +/** + * Register a new user + */ +export const registerMutation = ( + options?: Partial>, +): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await register({ + ...options, + ...fnOptions, + throwOnError: true, + }); + return data; + }, + }; + return mutationOptions; +}; + +/** + * Login with username and password + */ +export const loginMutation = ( + options?: Partial>, +): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await login({ + ...options, + ...fnOptions, + throwOnError: true, + }); + return data; + }, + }; + return mutationOptions; +}; + +/** + * Logout current user + */ +export const logoutMutation = ( + options?: Partial>, +): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await logout({ + ...options, + ...fnOptions, + throwOnError: true, + }); + return data; + }, + }; + return mutationOptions; +}; export type QueryKey = [ Pick & { @@ -121,7 +196,7 @@ const createQueryKey = ( ): [QueryKey[0]] => { const params: QueryKey[0] = { _id: id, - baseUrl: options?.baseUrl || (options?.client ?? _heyApiClient).getConfig().baseUrl, + baseUrl: options?.baseUrl || (options?.client ?? client).getConfig().baseUrl, } as QueryKey[0]; if (infinite) { params._infinite = infinite; @@ -144,130 +219,13 @@ const createQueryKey = ( return [params]; }; -export const registerQueryKey = (options?: Options) => createQueryKey("register", options); - -/** - * Register a new user - */ -export const registerOptions = (options?: Options) => { - return queryOptions({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await register({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: registerQueryKey(options), - }); -}; - -/** - * Register a new user - */ -export const registerMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions> = { - mutationFn: async (localOptions) => { - const { data } = await register({ - ...options, - ...localOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; -}; - -export const loginQueryKey = (options?: Options) => createQueryKey("login", options); - -/** - * Login with username and password - */ -export const loginOptions = (options?: Options) => { - return queryOptions({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await login({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: loginQueryKey(options), - }); -}; - -/** - * Login with username and password - */ -export const loginMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions> = { - mutationFn: async (localOptions) => { - const { data } = await login({ - ...options, - ...localOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; -}; - -export const logoutQueryKey = (options?: Options) => createQueryKey("logout", options); - -/** - * Logout current user - */ -export const logoutOptions = (options?: Options) => { - return queryOptions({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await logout({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: logoutQueryKey(options), - }); -}; - -/** - * Logout current user - */ -export const logoutMutation = ( - options?: Partial>, -): UseMutationOptions> => { - const mutationOptions: UseMutationOptions> = { - mutationFn: async (localOptions) => { - const { data } = await logout({ - ...options, - ...localOptions, - throwOnError: true, - }); - return data; - }, - }; - return mutationOptions; -}; - export const getMeQueryKey = (options?: Options) => createQueryKey("getMe", options); /** * Get current authenticated user */ -export const getMeOptions = (options?: Options) => { - return queryOptions({ +export const getMeOptions = (options?: Options) => + queryOptions>({ queryFn: async ({ queryKey, signal }) => { const { data } = await getMe({ ...options, @@ -279,15 +237,14 @@ export const getMeOptions = (options?: Options) => { }, queryKey: getMeQueryKey(options), }); -}; export const getStatusQueryKey = (options?: Options) => createQueryKey("getStatus", options); /** * Get authentication system status */ -export const getStatusOptions = (options?: Options) => { - return queryOptions({ +export const getStatusOptions = (options?: Options) => + queryOptions>({ queryFn: async ({ queryKey, signal }) => { const { data } = await getStatus({ ...options, @@ -299,28 +256,6 @@ export const getStatusOptions = (options?: Options) => { }, queryKey: getStatusQueryKey(options), }); -}; - -export const changePasswordQueryKey = (options?: Options) => - createQueryKey("changePassword", options); - -/** - * Change current user password - */ -export const changePasswordOptions = (options?: Options) => { - return queryOptions({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await changePassword({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: changePasswordQueryKey(options), - }); -}; /** * Change current user password @@ -329,10 +264,10 @@ export const changePasswordMutation = ( options?: Partial>, ): UseMutationOptions> => { const mutationOptions: UseMutationOptions> = { - mutationFn: async (localOptions) => { + mutationFn: async (fnOptions) => { const { data } = await changePassword({ ...options, - ...localOptions, + ...fnOptions, throwOnError: true, }); return data; @@ -346,8 +281,8 @@ export const listVolumesQueryKey = (options?: Options) => creat /** * List all volumes */ -export const listVolumesOptions = (options?: Options) => { - return queryOptions({ +export const listVolumesOptions = (options?: Options) => + queryOptions>({ queryFn: async ({ queryKey, signal }) => { const { data } = await listVolumes({ ...options, @@ -359,27 +294,6 @@ export const listVolumesOptions = (options?: Options) => { }, queryKey: listVolumesQueryKey(options), }); -}; - -export const createVolumeQueryKey = (options?: Options) => createQueryKey("createVolume", options); - -/** - * Create a new volume - */ -export const createVolumeOptions = (options?: Options) => { - return queryOptions({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await createVolume({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: createVolumeQueryKey(options), - }); -}; /** * Create a new volume @@ -388,10 +302,10 @@ export const createVolumeMutation = ( options?: Partial>, ): UseMutationOptions> => { const mutationOptions: UseMutationOptions> = { - mutationFn: async (localOptions) => { + mutationFn: async (fnOptions) => { const { data } = await createVolume({ ...options, - ...localOptions, + ...fnOptions, throwOnError: true, }); return data; @@ -400,27 +314,6 @@ export const createVolumeMutation = ( return mutationOptions; }; -export const testConnectionQueryKey = (options?: Options) => - createQueryKey("testConnection", options); - -/** - * Test connection to backend - */ -export const testConnectionOptions = (options?: Options) => { - return queryOptions({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await testConnection({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: testConnectionQueryKey(options), - }); -}; - /** * Test connection to backend */ @@ -428,10 +321,10 @@ export const testConnectionMutation = ( options?: Partial>, ): UseMutationOptions> => { const mutationOptions: UseMutationOptions> = { - mutationFn: async (localOptions) => { + mutationFn: async (fnOptions) => { const { data } = await testConnection({ ...options, - ...localOptions, + ...fnOptions, throwOnError: true, }); return data; @@ -447,10 +340,10 @@ export const deleteVolumeMutation = ( options?: Partial>, ): UseMutationOptions> => { const mutationOptions: UseMutationOptions> = { - mutationFn: async (localOptions) => { + mutationFn: async (fnOptions) => { const { data } = await deleteVolume({ ...options, - ...localOptions, + ...fnOptions, throwOnError: true, }); return data; @@ -464,8 +357,8 @@ export const getVolumeQueryKey = (options: Options) => createQuer /** * Get a volume by name */ -export const getVolumeOptions = (options: Options) => { - return queryOptions({ +export const getVolumeOptions = (options: Options) => + queryOptions>({ queryFn: async ({ queryKey, signal }) => { const { data } = await getVolume({ ...options, @@ -477,7 +370,6 @@ export const getVolumeOptions = (options: Options) => { }, queryKey: getVolumeQueryKey(options), }); -}; /** * Update a volume's configuration @@ -486,10 +378,10 @@ export const updateVolumeMutation = ( options?: Partial>, ): UseMutationOptions> => { const mutationOptions: UseMutationOptions> = { - mutationFn: async (localOptions) => { + mutationFn: async (fnOptions) => { const { data } = await updateVolume({ ...options, - ...localOptions, + ...fnOptions, throwOnError: true, }); return data; @@ -504,8 +396,13 @@ export const getContainersUsingVolumeQueryKey = (options: Options) => { - return queryOptions({ +export const getContainersUsingVolumeOptions = (options: Options) => + queryOptions< + GetContainersUsingVolumeResponse, + DefaultError, + GetContainersUsingVolumeResponse, + ReturnType + >({ queryFn: async ({ queryKey, signal }) => { const { data } = await getContainersUsingVolume({ ...options, @@ -517,27 +414,6 @@ export const getContainersUsingVolumeOptions = (options: Options) => createQueryKey("mountVolume", options); - -/** - * Mount a volume - */ -export const mountVolumeOptions = (options: Options) => { - return queryOptions({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await mountVolume({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: mountVolumeQueryKey(options), - }); -}; /** * Mount a volume @@ -546,10 +422,10 @@ export const mountVolumeMutation = ( options?: Partial>, ): UseMutationOptions> => { const mutationOptions: UseMutationOptions> = { - mutationFn: async (localOptions) => { + mutationFn: async (fnOptions) => { const { data } = await mountVolume({ ...options, - ...localOptions, + ...fnOptions, throwOnError: true, }); return data; @@ -558,26 +434,6 @@ export const mountVolumeMutation = ( return mutationOptions; }; -export const unmountVolumeQueryKey = (options: Options) => createQueryKey("unmountVolume", options); - -/** - * Unmount a volume - */ -export const unmountVolumeOptions = (options: Options) => { - return queryOptions({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await unmountVolume({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: unmountVolumeQueryKey(options), - }); -}; - /** * Unmount a volume */ @@ -585,10 +441,10 @@ export const unmountVolumeMutation = ( options?: Partial>, ): UseMutationOptions> => { const mutationOptions: UseMutationOptions> = { - mutationFn: async (localOptions) => { + mutationFn: async (fnOptions) => { const { data } = await unmountVolume({ ...options, - ...localOptions, + ...fnOptions, throwOnError: true, }); return data; @@ -597,27 +453,6 @@ export const unmountVolumeMutation = ( return mutationOptions; }; -export const healthCheckVolumeQueryKey = (options: Options) => - createQueryKey("healthCheckVolume", options); - -/** - * Perform a health check on a volume - */ -export const healthCheckVolumeOptions = (options: Options) => { - return queryOptions({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await healthCheckVolume({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: healthCheckVolumeQueryKey(options), - }); -}; - /** * Perform a health check on a volume */ @@ -625,10 +460,10 @@ export const healthCheckVolumeMutation = ( options?: Partial>, ): UseMutationOptions> => { const mutationOptions: UseMutationOptions> = { - mutationFn: async (localOptions) => { + mutationFn: async (fnOptions) => { const { data } = await healthCheckVolume({ ...options, - ...localOptions, + ...fnOptions, throwOnError: true, }); return data; @@ -642,8 +477,8 @@ export const listFilesQueryKey = (options: Options) => createQuer /** * List files in a volume directory */ -export const listFilesOptions = (options: Options) => { - return queryOptions({ +export const listFilesOptions = (options: Options) => + queryOptions>({ queryFn: async ({ queryKey, signal }) => { const { data } = await listFiles({ ...options, @@ -655,7 +490,6 @@ export const listFilesOptions = (options: Options) => { }, queryKey: listFilesQueryKey(options), }); -}; export const browseFilesystemQueryKey = (options?: Options) => createQueryKey("browseFilesystem", options); @@ -663,8 +497,13 @@ export const browseFilesystemQueryKey = (options?: Options /** * Browse directories on the host filesystem */ -export const browseFilesystemOptions = (options?: Options) => { - return queryOptions({ +export const browseFilesystemOptions = (options?: Options) => + queryOptions< + BrowseFilesystemResponse, + DefaultError, + BrowseFilesystemResponse, + ReturnType + >({ queryFn: async ({ queryKey, signal }) => { const { data } = await browseFilesystem({ ...options, @@ -676,7 +515,6 @@ export const browseFilesystemOptions = (options?: Options) }, queryKey: browseFilesystemQueryKey(options), }); -}; export const listRepositoriesQueryKey = (options?: Options) => createQueryKey("listRepositories", options); @@ -684,8 +522,13 @@ export const listRepositoriesQueryKey = (options?: Options /** * List all repositories */ -export const listRepositoriesOptions = (options?: Options) => { - return queryOptions({ +export const listRepositoriesOptions = (options?: Options) => + queryOptions< + ListRepositoriesResponse, + DefaultError, + ListRepositoriesResponse, + ReturnType + >({ queryFn: async ({ queryKey, signal }) => { const { data } = await listRepositories({ ...options, @@ -697,28 +540,6 @@ export const listRepositoriesOptions = (options?: Options) }, queryKey: listRepositoriesQueryKey(options), }); -}; - -export const createRepositoryQueryKey = (options?: Options) => - createQueryKey("createRepository", options); - -/** - * Create a new restic repository - */ -export const createRepositoryOptions = (options?: Options) => { - return queryOptions({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await createRepository({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: createRepositoryQueryKey(options), - }); -}; /** * Create a new restic repository @@ -727,10 +548,10 @@ export const createRepositoryMutation = ( options?: Partial>, ): UseMutationOptions> => { const mutationOptions: UseMutationOptions> = { - mutationFn: async (localOptions) => { + mutationFn: async (fnOptions) => { const { data } = await createRepository({ ...options, - ...localOptions, + ...fnOptions, throwOnError: true, }); return data; @@ -745,8 +566,13 @@ export const listRcloneRemotesQueryKey = (options?: Options) => { - return queryOptions({ +export const listRcloneRemotesOptions = (options?: Options) => + queryOptions< + ListRcloneRemotesResponse, + DefaultError, + ListRcloneRemotesResponse, + ReturnType + >({ queryFn: async ({ queryKey, signal }) => { const { data } = await listRcloneRemotes({ ...options, @@ -758,7 +584,6 @@ export const listRcloneRemotesOptions = (options?: Options>, ): UseMutationOptions> => { const mutationOptions: UseMutationOptions> = { - mutationFn: async (localOptions) => { + mutationFn: async (fnOptions) => { const { data } = await deleteRepository({ ...options, - ...localOptions, + ...fnOptions, throwOnError: true, }); return data; @@ -784,8 +609,8 @@ export const getRepositoryQueryKey = (options: Options) => cr /** * Get a single repository by name */ -export const getRepositoryOptions = (options: Options) => { - return queryOptions({ +export const getRepositoryOptions = (options: Options) => + queryOptions>({ queryFn: async ({ queryKey, signal }) => { const { data } = await getRepository({ ...options, @@ -797,15 +622,14 @@ export const getRepositoryOptions = (options: Options) => { }, queryKey: getRepositoryQueryKey(options), }); -}; export const listSnapshotsQueryKey = (options: Options) => createQueryKey("listSnapshots", options); /** * List all snapshots in a repository */ -export const listSnapshotsOptions = (options: Options) => { - return queryOptions({ +export const listSnapshotsOptions = (options: Options) => + queryOptions>({ queryFn: async ({ queryKey, signal }) => { const { data } = await listSnapshots({ ...options, @@ -817,7 +641,6 @@ export const listSnapshotsOptions = (options: Options) => { }, queryKey: listSnapshotsQueryKey(options), }); -}; export const getSnapshotDetailsQueryKey = (options: Options) => createQueryKey("getSnapshotDetails", options); @@ -825,8 +648,13 @@ export const getSnapshotDetailsQueryKey = (options: Options) => { - return queryOptions({ +export const getSnapshotDetailsOptions = (options: Options) => + queryOptions< + GetSnapshotDetailsResponse, + DefaultError, + GetSnapshotDetailsResponse, + ReturnType + >({ queryFn: async ({ queryKey, signal }) => { const { data } = await getSnapshotDetails({ ...options, @@ -838,7 +666,6 @@ export const getSnapshotDetailsOptions = (options: Options) => createQueryKey("listSnapshotFiles", options); @@ -846,8 +673,13 @@ export const listSnapshotFilesQueryKey = (options: Options) => { - return queryOptions({ +export const listSnapshotFilesOptions = (options: Options) => + queryOptions< + ListSnapshotFilesResponse, + DefaultError, + ListSnapshotFilesResponse, + ReturnType + >({ queryFn: async ({ queryKey, signal }) => { const { data } = await listSnapshotFiles({ ...options, @@ -859,28 +691,6 @@ export const listSnapshotFilesOptions = (options: Options }, queryKey: listSnapshotFilesQueryKey(options), }); -}; - -export const restoreSnapshotQueryKey = (options: Options) => - createQueryKey("restoreSnapshot", options); - -/** - * Restore a snapshot to a target path on the filesystem - */ -export const restoreSnapshotOptions = (options: Options) => { - return queryOptions({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await restoreSnapshot({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: restoreSnapshotQueryKey(options), - }); -}; /** * Restore a snapshot to a target path on the filesystem @@ -889,10 +699,10 @@ export const restoreSnapshotMutation = ( options?: Partial>, ): UseMutationOptions> => { const mutationOptions: UseMutationOptions> = { - mutationFn: async (localOptions) => { + mutationFn: async (fnOptions) => { const { data } = await restoreSnapshot({ ...options, - ...localOptions, + ...fnOptions, throwOnError: true, }); return data; @@ -901,27 +711,6 @@ export const restoreSnapshotMutation = ( return mutationOptions; }; -export const doctorRepositoryQueryKey = (options: Options) => - createQueryKey("doctorRepository", options); - -/** - * Run doctor operations on a repository to fix common issues (unlock, check, repair index). Use this when the repository is locked or has errors. - */ -export const doctorRepositoryOptions = (options: Options) => { - return queryOptions({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await doctorRepository({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: doctorRepositoryQueryKey(options), - }); -}; - /** * Run doctor operations on a repository to fix common issues (unlock, check, repair index). Use this when the repository is locked or has errors. */ @@ -929,10 +718,10 @@ export const doctorRepositoryMutation = ( options?: Partial>, ): UseMutationOptions> => { const mutationOptions: UseMutationOptions> = { - mutationFn: async (localOptions) => { + mutationFn: async (fnOptions) => { const { data } = await doctorRepository({ ...options, - ...localOptions, + ...fnOptions, throwOnError: true, }); return data; @@ -947,8 +736,13 @@ export const listBackupSchedulesQueryKey = (options?: Options) => { - return queryOptions({ +export const listBackupSchedulesOptions = (options?: Options) => + queryOptions< + ListBackupSchedulesResponse, + DefaultError, + ListBackupSchedulesResponse, + ReturnType + >({ queryFn: async ({ queryKey, signal }) => { const { data } = await listBackupSchedules({ ...options, @@ -960,28 +754,6 @@ export const listBackupSchedulesOptions = (options?: Options) => - createQueryKey("createBackupSchedule", options); - -/** - * Create a new backup schedule for a volume - */ -export const createBackupScheduleOptions = (options?: Options) => { - return queryOptions({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await createBackupSchedule({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: createBackupScheduleQueryKey(options), - }); -}; /** * Create a new backup schedule for a volume @@ -994,10 +766,10 @@ export const createBackupScheduleMutation = ( DefaultError, Options > = { - mutationFn: async (localOptions) => { + mutationFn: async (fnOptions) => { const { data } = await createBackupSchedule({ ...options, - ...localOptions, + ...fnOptions, throwOnError: true, }); return data; @@ -1017,10 +789,10 @@ export const deleteBackupScheduleMutation = ( DefaultError, Options > = { - mutationFn: async (localOptions) => { + mutationFn: async (fnOptions) => { const { data } = await deleteBackupSchedule({ ...options, - ...localOptions, + ...fnOptions, throwOnError: true, }); return data; @@ -1035,8 +807,13 @@ export const getBackupScheduleQueryKey = (options: Options) => { - return queryOptions({ +export const getBackupScheduleOptions = (options: Options) => + queryOptions< + GetBackupScheduleResponse, + DefaultError, + GetBackupScheduleResponse, + ReturnType + >({ queryFn: async ({ queryKey, signal }) => { const { data } = await getBackupSchedule({ ...options, @@ -1048,7 +825,6 @@ export const getBackupScheduleOptions = (options: Options }, queryKey: getBackupScheduleQueryKey(options), }); -}; /** * Update a backup schedule @@ -1061,10 +837,10 @@ export const updateBackupScheduleMutation = ( DefaultError, Options > = { - mutationFn: async (localOptions) => { + mutationFn: async (fnOptions) => { const { data } = await updateBackupSchedule({ ...options, - ...localOptions, + ...fnOptions, throwOnError: true, }); return data; @@ -1079,8 +855,13 @@ export const getBackupScheduleForVolumeQueryKey = (options: Options) => { - return queryOptions({ +export const getBackupScheduleForVolumeOptions = (options: Options) => + queryOptions< + GetBackupScheduleForVolumeResponse, + DefaultError, + GetBackupScheduleForVolumeResponse, + ReturnType + >({ queryFn: async ({ queryKey, signal }) => { const { data } = await getBackupScheduleForVolume({ ...options, @@ -1092,27 +873,6 @@ export const getBackupScheduleForVolumeOptions = (options: Options) => createQueryKey("runBackupNow", options); - -/** - * Trigger a backup immediately for a schedule - */ -export const runBackupNowOptions = (options: Options) => { - return queryOptions({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await runBackupNow({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: runBackupNowQueryKey(options), - }); -}; /** * Trigger a backup immediately for a schedule @@ -1121,10 +881,10 @@ export const runBackupNowMutation = ( options?: Partial>, ): UseMutationOptions> => { const mutationOptions: UseMutationOptions> = { - mutationFn: async (localOptions) => { + mutationFn: async (fnOptions) => { const { data } = await runBackupNow({ ...options, - ...localOptions, + ...fnOptions, throwOnError: true, }); return data; @@ -1133,26 +893,6 @@ export const runBackupNowMutation = ( return mutationOptions; }; -export const stopBackupQueryKey = (options: Options) => createQueryKey("stopBackup", options); - -/** - * Stop a backup that is currently in progress - */ -export const stopBackupOptions = (options: Options) => { - return queryOptions({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await stopBackup({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: stopBackupQueryKey(options), - }); -}; - /** * Stop a backup that is currently in progress */ @@ -1160,10 +900,10 @@ export const stopBackupMutation = ( options?: Partial>, ): UseMutationOptions> => { const mutationOptions: UseMutationOptions> = { - mutationFn: async (localOptions) => { + mutationFn: async (fnOptions) => { const { data } = await stopBackup({ ...options, - ...localOptions, + ...fnOptions, throwOnError: true, }); return data; @@ -1177,8 +917,8 @@ export const getSystemInfoQueryKey = (options?: Options) => c /** * Get system information including available capabilities */ -export const getSystemInfoOptions = (options?: Options) => { - return queryOptions({ +export const getSystemInfoOptions = (options?: Options) => + queryOptions>({ queryFn: async ({ queryKey, signal }) => { const { data } = await getSystemInfo({ ...options, @@ -1190,28 +930,6 @@ export const getSystemInfoOptions = (options?: Options) => { }, queryKey: getSystemInfoQueryKey(options), }); -}; - -export const downloadResticPasswordQueryKey = (options?: Options) => - createQueryKey("downloadResticPassword", options); - -/** - * Download the Restic password file for backup recovery. Requires password re-authentication. - */ -export const downloadResticPasswordOptions = (options?: Options) => { - return queryOptions({ - queryFn: async ({ queryKey, signal }) => { - const { data } = await downloadResticPassword({ - ...options, - ...queryKey[0], - signal, - throwOnError: true, - }); - return data; - }, - queryKey: downloadResticPasswordQueryKey(options), - }); -}; /** * Download the Restic password file for backup recovery. Requires password re-authentication. @@ -1224,10 +942,10 @@ export const downloadResticPasswordMutation = ( DefaultError, Options > = { - mutationFn: async (localOptions) => { + mutationFn: async (fnOptions) => { const { data } = await downloadResticPassword({ ...options, - ...localOptions, + ...fnOptions, throwOnError: true, }); return data; diff --git a/app/api-client/client.gen.ts b/app/client/api-client/client.gen.ts similarity index 57% rename from app/api-client/client.gen.ts rename to app/client/api-client/client.gen.ts index d30d8c1d..26953172 100644 --- a/app/api-client/client.gen.ts +++ b/app/client/api-client/client.gen.ts @@ -1,7 +1,7 @@ // This file is auto-generated by @hey-api/openapi-ts -import type { ClientOptions } from "./types.gen"; -import { type Config, type ClientOptions as DefaultClientOptions, createClient, createConfig } from "./client"; +import { type ClientOptions, type Config, createClient, createConfig } from "./client"; +import type { ClientOptions as ClientOptions2 } from "./types.gen"; /** * The `createClientConfig()` function will be called on client initialization @@ -11,12 +11,12 @@ import { type Config, type ClientOptions as DefaultClientOptions, createClient, * `setConfig()`. This is useful for example if you're using Next.js * to ensure your client always has the correct values. */ -export type CreateClientConfig = ( - override?: Config, -) => Config & T>; +export type CreateClientConfig = ( + override?: Config, +) => Config & T>; export const client = createClient( - createConfig({ + createConfig({ baseUrl: "http://192.168.2.42:4096", }), ); diff --git a/app/api-client/client/client.gen.ts b/app/client/api-client/client/client.gen.ts similarity index 53% rename from app/api-client/client/client.gen.ts rename to app/client/api-client/client/client.gen.ts index dc408891..e30d8adb 100644 --- a/app/api-client/client/client.gen.ts +++ b/app/client/api-client/client/client.gen.ts @@ -1,6 +1,9 @@ // This file is auto-generated by @hey-api/openapi-ts -import type { Client, Config, 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, @@ -28,7 +31,7 @@ export const createClient = (config: Config = {}): Client => { const interceptors = createInterceptors(); - const request: Client["request"] = async (options) => { + const beforeRequest = async (options: RequestOptions) => { const opts = { ..._config, ...options, @@ -48,25 +51,32 @@ export const createClient = (config: Config = {}): Client => { await opts.requestValidator(opts); } - if (opts.body && opts.bodySerializer) { + 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.serializedBody === undefined || opts.serializedBody === "") { + if (opts.body === undefined || opts.serializedBody === "") { opts.headers.delete("Content-Type"); } const url = buildUrl(opts); + + 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: opts.serializedBody, + body: getValidRequestBody(opts), }; let request = new Request(url, requestInit); - for (const fn of interceptors.request._fns) { + for (const fn of interceptors.request.fns) { if (fn) { request = await fn(request, opts); } @@ -75,9 +85,37 @@ export const createClient = (config: Config = {}): Client => { // 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 = await _fetch(request); + let response: Response; - for (const fn of interceptors.response._fns) { + 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; + } + } + + finalError = finalError || ({} as unknown); + + if (opts.throwOnError) { + throw finalError; + } + + // 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); } @@ -89,18 +127,36 @@ export const createClient = (config: Config = {}): Client => { }; 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: {}, + data: emptyData, ...result, }; } - const parseAs = - (opts.parseAs === "auto" ? getParseAs(response.headers.get("Content-Type")) : opts.parseAs) ?? "json"; - let data: any; switch (parseAs) { case "arrayBuffer": @@ -149,7 +205,7 @@ export const createClient = (config: Config = {}): Client => { const error = jsonError ?? textError; let finalError = error; - for (const fn of interceptors.error._fns) { + for (const fn of interceptors.error.fns) { if (fn) { finalError = (await fn(error, response, request, opts)) as string; } @@ -170,20 +226,53 @@ export const createClient = (config: Config = {}): Client => { }; }; + 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; + }, + url, + }); + }; + return { buildUrl, - connect: (options) => request({ ...options, method: "CONNECT" }), - delete: (options) => request({ ...options, method: "DELETE" }), - get: (options) => request({ ...options, method: "GET" }), + connect: makeMethodFn("CONNECT"), + delete: makeMethodFn("DELETE"), + get: makeMethodFn("GET"), getConfig, - head: (options) => request({ ...options, method: "HEAD" }), + head: makeMethodFn("HEAD"), interceptors, - options: (options) => request({ ...options, method: "OPTIONS" }), - patch: (options) => request({ ...options, method: "PATCH" }), - post: (options) => request({ ...options, method: "POST" }), - put: (options) => request({ ...options, method: "PUT" }), + options: makeMethodFn("OPTIONS"), + patch: makeMethodFn("PATCH"), + post: makeMethodFn("POST"), + put: makeMethodFn("PUT"), request, setConfig, - trace: (options) => request({ ...options, method: "TRACE" }), - }; + 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/api-client/client/index.ts b/app/client/api-client/client/index.ts similarity index 89% rename from app/api-client/client/index.ts rename to app/client/api-client/client/index.ts index 3d14a8e2..99ab72d0 100644 --- a/app/api-client/client/index.ts +++ b/app/client/api-client/client/index.ts @@ -8,6 +8,7 @@ export { urlSearchParamsBodySerializer, } from "../core/bodySerializer.gen"; export { buildClientParams } from "../core/params.gen"; +export { serializeQueryKeyValue } from "../core/queryKeySerializer.gen"; export { createClient } from "./client.gen"; export type { Client, @@ -15,7 +16,6 @@ export type { Config, CreateClientConfig, Options, - OptionsLegacyParser, RequestOptions, RequestResult, ResolvedRequestOptions, diff --git a/app/api-client/client/types.gen.ts b/app/client/api-client/client/types.gen.ts similarity index 80% rename from app/api-client/client/types.gen.ts rename to app/client/api-client/client/types.gen.ts index 605d90fa..71ed2eb6 100644 --- a/app/api-client/client/types.gen.ts +++ b/app/client/api-client/client/types.gen.ts @@ -1,6 +1,7 @@ // 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"; @@ -19,7 +20,7 @@ export interface Config * * @default globalThis.fetch */ - fetch?: (request: Request) => ReturnType; + fetch?: typeof fetch; /** * Please don't use the Fetch client for Next.js applications. The `next` * options won't have any effect. @@ -51,13 +52,18 @@ export interface Config } export interface RequestOptions< + TData = unknown, TResponseStyle extends ResponseStyle = "fields", ThrowOnError extends boolean = boolean, Url extends string = string, > extends Config<{ - responseStyle: TResponseStyle; - throwOnError: ThrowOnError; - }> { + responseStyle: TResponseStyle; + throwOnError: ThrowOnError; + }>, + Pick< + ServerSentEventsOptions, + "onSseError" | "onSseEvent" | "sseDefaultRetryDelay" | "sseMaxRetryAttempts" | "sseMaxRetryDelay" + > { /** * Any body that you want to add to your request. * @@ -77,7 +83,7 @@ export interface ResolvedRequestOptions< TResponseStyle extends ResponseStyle = "fields", ThrowOnError extends boolean = boolean, Url extends string = string, -> extends RequestOptions { +> extends RequestOptions { serializedBody?: string; } @@ -128,17 +134,26 @@ type MethodFn = < 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", +>( + options: Omit, "method">, +) => Promise>; + type RequestFn = < 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 = < @@ -149,10 +164,10 @@ type BuildUrlFn = < url: string; }, >( - options: Pick & Options, + options: TData & Options, ) => string; -export type Client = CoreClient & { +export type Client = CoreClient & { interceptors: Middleware; }; @@ -181,21 +196,7 @@ 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"> & Omit; - -export type OptionsLegacyParser< - TData = unknown, - ThrowOnError extends boolean = boolean, - TResponseStyle extends ResponseStyle = "fields", -> = TData extends { body?: any } - ? TData extends { headers?: any } - ? OmitKeys, "body" | "headers" | "url"> & TData - : OmitKeys, "body" | "url"> & - TData & - Pick, "headers"> - : TData extends { headers?: any } - ? OmitKeys, "headers" | "url"> & - TData & - Pick, "body"> - : OmitKeys, "url"> & TData; +> = OmitKeys, "body" | "path" | "query" | "url"> & + ([TData] extends [never] ? unknown : Omit); diff --git a/app/api-client/client/utils.gen.ts b/app/client/api-client/client/utils.gen.ts similarity index 61% rename from app/api-client/client/utils.gen.ts rename to app/client/api-client/client/utils.gen.ts index 3fe22baa..fb460443 100644 --- a/app/api-client/client/utils.gen.ts +++ b/app/client/api-client/client/utils.gen.ts @@ -1,88 +1,13 @@ // This file is auto-generated by @hey-api/openapi-ts import { getAuthToken } from "../core/auth.gen"; -import type { QuerySerializer, QuerySerializerOptions } from "../core/bodySerializer.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"; -interface PathSerializer { - path: Record; - url: string; -} - -const PATH_PARAM_RE = /\{[^{}]+\}/g; - -type ArrayStyle = "form" | "spaceDelimited" | "pipeDelimited"; -type MatrixStyle = "label" | "matrix" | "simple"; -type ArraySeparatorStyle = ArrayStyle | MatrixStyle; - -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"; - - 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"; - } - - const value = path[name]; - - if (value === undefined || value === null) { - 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 (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; -}; - -export const createQuerySerializer = ({ allowReserved, array, object }: QuerySerializerOptions = {}) => { +export const createQuerySerializer = ({ parameters = {}, ...args }: QuerySerializerOptions = {}) => { const querySerializer = (queryParams: T) => { const search: string[] = []; if (queryParams && typeof queryParams === "object") { @@ -93,29 +18,31 @@ export const createQuerySerializer = ({ allowReserved, array, objec continue; } + const options = parameters[name] || args; + if (Array.isArray(value)) { const serializedArray = serializeArrayParam({ - allowReserved, + allowReserved: options.allowReserved, explode: true, name, style: "form", value, - ...array, + ...options.array, }); if (serializedArray) search.push(serializedArray); } else if (typeof value === "object") { const serializedObject = serializeObjectParam({ - allowReserved, + allowReserved: options.allowReserved, explode: true, name, style: "deepObject", value: value as Record, - ...object, + ...options.object, }); if (serializedObject) search.push(serializedObject); } else { const serializedPrimitive = serializePrimitiveParam({ - allowReserved, + allowReserved: options.allowReserved, name, value: value as string, }); @@ -216,8 +143,8 @@ export const setAuthParams = async ({ } }; -export const buildUrl: Client["buildUrl"] = (options) => { - const url = getUrl({ +export const buildUrl: Client["buildUrl"] = (options) => + getUrl({ baseUrl: options.baseUrl as string, path: options.path, query: options.query, @@ -227,36 +154,6 @@ export const buildUrl: Client["buildUrl"] = (options) => { : createQuerySerializer(options.querySerializer), url: options.url, }); - return url; -}; - -export const getUrl = ({ - baseUrl, - path, - query, - querySerializer, - url: _url, -}: { - 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; -}; export const mergeConfigs = (a: Config, b: Config): Config => { const config = { ...a, ...b }; @@ -267,14 +164,22 @@ export const mergeConfigs = (a: Config, b: Config): Config => { return config; }; +const headersEntries = (headers: Headers): Array<[string, string]> => { + 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 || typeof header !== "object") { + if (!header) { continue; } - const iterator = header instanceof Headers ? header.entries() : Object.entries(header); + const iterator = header instanceof Headers ? headersEntries(header) : Object.entries(header); for (const [key, value] of iterator) { if (value === null) { @@ -305,61 +210,53 @@ type ReqInterceptor = (request: Req, options: Options) => Req | Pr type ResInterceptor = (response: Res, request: Req, options: Options) => Res | Promise; class Interceptors { - _fns: (Interceptor | null)[]; + fns: Array = []; - constructor() { - this._fns = []; + clear(): void { + this.fns = []; } - clear() { - this._fns = []; + 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]); } getInterceptorIndex(id: number | Interceptor): number { if (typeof id === "number") { - return this._fns[id] ? id : -1; - } else { - return this._fns.indexOf(id); + return this.fns[id] ? id : -1; } - } - exists(id: number | Interceptor) { - const index = this.getInterceptorIndex(id); - return !!this._fns[index]; + return this.fns.indexOf(id); } - eject(id: number | Interceptor) { + update(id: number | Interceptor, fn: Interceptor): number | Interceptor | false { const index = this.getInterceptorIndex(id); - if (this._fns[index]) { - this._fns[index] = null; - } - } - - update(id: number | Interceptor, fn: Interceptor) { - const index = this.getInterceptorIndex(id); - if (this._fns[index]) { - this._fns[index] = fn; + if (this.fns[index]) { + this.fns[index] = fn; return id; - } else { - return false; } + return false; } - use(fn: Interceptor) { - this._fns = [...this._fns, fn]; - return this._fns.length - 1; + use(fn: Interceptor): number { + this.fns.push(fn); + return this.fns.length - 1; } } -// `createInterceptors()` response, meant for external use as it does not -// expose internals export interface Middleware { - error: Pick>, "eject" | "use">; - request: Pick>, "eject" | "use">; - response: Pick>, "eject" | "use">; + error: Interceptors>; + request: Interceptors>; + response: Interceptors>; } -// do not add `Middleware` as return type so we can use _fns internally -export const createInterceptors = () => ({ +export const createInterceptors = (): Middleware => ({ error: new Interceptors>(), request: new Interceptors>(), response: new Interceptors>(), diff --git a/app/api-client/core/auth.gen.ts b/app/client/api-client/core/auth.gen.ts similarity index 100% rename from app/api-client/core/auth.gen.ts rename to app/client/api-client/core/auth.gen.ts diff --git a/app/api-client/core/bodySerializer.gen.ts b/app/client/api-client/core/bodySerializer.gen.ts similarity index 82% rename from app/api-client/core/bodySerializer.gen.ts rename to app/client/api-client/core/bodySerializer.gen.ts index 256d42d9..10e7b3a6 100644 --- a/app/api-client/core/bodySerializer.gen.ts +++ b/app/client/api-client/core/bodySerializer.gen.ts @@ -6,11 +6,19 @@ export type QuerySerializer = (query: Record) => string; export type BodySerializer = (body: any) => any; -export interface QuerySerializerOptions { +type QuerySerializerOptionsObject = { allowReserved?: boolean; - array?: SerializerOptions; - object?: SerializerOptions; -} + 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; +}; const serializeFormDataPair = (data: FormData, key: string, value: unknown): void => { if (typeof value === "string" || value instanceof Blob) { diff --git a/app/api-client/core/params.gen.ts b/app/client/api-client/core/params.gen.ts similarity index 78% rename from app/api-client/core/params.gen.ts rename to app/client/api-client/core/params.gen.ts index db9fb4f5..c1fb15c5 100644 --- a/app/api-client/core/params.gen.ts +++ b/app/client/api-client/core/params.gen.ts @@ -22,6 +22,17 @@ export type Field = */ 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 { @@ -41,10 +52,14 @@ const extraPrefixes = Object.entries(extraPrefixesMap); type KeyMap = Map< string, - { - in: Slot; - map?: string; - } + | { + in: Slot; + map?: string; + } + | { + in?: never; + map: Slot; + } >; const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => { @@ -60,6 +75,10 @@ const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => { map: config.map, }); } + } else if ("key" in config) { + map.set(config.key, { + map: config.map, + }); } else if (config.args) { buildKeyMap(config.args, map); } @@ -108,7 +127,9 @@ export const buildClientParams = (args: ReadonlyArray, fields: FieldsCo if (config.key) { const field = map.get(config.key)!; const name = field.map || config.key; - (params[field.in] as Record)[name] = arg; + if (field.in) { + (params[field.in] as Record)[name] = arg; + } } else { params.body = arg; } @@ -117,16 +138,20 @@ export const buildClientParams = (args: ReadonlyArray, fields: FieldsCo const field = map.get(key); if (field) { - const name = field.map || key; - (params[field.in] as Record)[name] = value; + 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 { - for (const [slot, allowed] of Object.entries(config.allowExtra ?? {})) { + } 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; diff --git a/app/api-client/core/pathSerializer.gen.ts b/app/client/api-client/core/pathSerializer.gen.ts similarity index 100% rename from app/api-client/core/pathSerializer.gen.ts rename to app/client/api-client/core/pathSerializer.gen.ts diff --git a/app/client/api-client/core/queryKeySerializer.gen.ts b/app/client/api-client/core/queryKeySerializer.gen.ts new file mode 100644 index 00000000..b3e87676 --- /dev/null +++ b/app/client/api-client/core/queryKeySerializer.gen.ts @@ -0,0 +1,111 @@ +// This file is auto-generated by @hey-api/openapi-ts + +/** + * JSON-friendly union that mirrors what Pinia Colada can hash. + */ +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; +}; + +/** + * 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; + } +}; + +/** + * 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; +}; + +/** + * 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 = {}; + + 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]; + } + } + + 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 (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { + 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(); + } + + if (Array.isArray(value)) { + return stringifyToJsonValue(value); + } + + if (typeof URLSearchParams !== "undefined" && value instanceof URLSearchParams) { + return serializeSearchParams(value); + } + + if (isPlainObject(value)) { + return stringifyToJsonValue(value); + } + + return undefined; +}; diff --git a/app/client/api-client/core/serverSentEvents.gen.ts b/app/client/api-client/core/serverSentEvents.gen.ts new file mode 100644 index 00000000..8a27c459 --- /dev/null +++ b/app/client/api-client/core/serverSentEvents.gen.ts @@ -0,0 +1,237 @@ +// This file is auto-generated by @hey-api/openapi-ts + +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 interface StreamEvent { + data: TData; + event?: string; + id?: string; + retry?: number; +} + +export type ServerSentEventsResult = { + stream: AsyncGenerator ? TData[keyof TData] : TData, TReturn, TNext>; +}; + +export const createSseClient = ({ + onRequest, + onSseError, + onSseEvent, + responseTransformer, + responseValidator, + sseDefaultRetryDelay, + sseMaxRetryAttempts, + sseMaxRetryDelay, + sseSleepFn, + url, + ...options +}: ServerSentEventsOptions): ServerSentEventsResult => { + let lastEventId: string | undefined; + + 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; + + while (true) { + if (signal.aborted) break; + + attempt++; + + const headers = + options.headers instanceof Headers + ? options.headers + : new Headers(options.headers as Record | undefined); + + 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); + + if (!response.ok) throw new Error(`SSE failed: ${response.status} ${response.statusText}`); + + if (!response.body) throw new Error("No body in SSE response"); + + const reader = response.body.pipeThrough(new TextDecoderStream()).getReader(); + + let buffer = ""; + + const abortHandler = () => { + try { + reader.cancel(); + } catch { + // noop + } + }; + + signal.addEventListener("abort", abortHandler); + + try { + while (true) { + const { done, value } = await reader.read(); + if (done) break; + buffer += value; + + 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 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; + + 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 (responseTransformer) { + data = await responseTransformer(data); + } + } + + onSseEvent?.({ + data, + event: eventName, + id: lastEventId, + retry: retryDelay, + }); + + 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); + + 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); + } + } + }; + + const stream = createStream(); + + return { stream }; +}; diff --git a/app/api-client/core/types.gen.ts b/app/client/api-client/core/types.gen.ts similarity index 87% rename from app/api-client/core/types.gen.ts rename to app/client/api-client/core/types.gen.ts index be24654f..62252e53 100644 --- a/app/api-client/core/types.gen.ts +++ b/app/client/api-client/core/types.gen.ts @@ -3,24 +3,19 @@ import type { Auth, AuthToken } from "./auth.gen"; import type { BodySerializer, QuerySerializer, QuerySerializerOptions } from "./bodySerializer.gen"; -export interface Client { +export type HttpMethod = "connect" | "delete" | "get" | "head" | "options" | "patch" | "post" | "put" | "trace"; + +export type Client = { /** * Returns the final request URL. */ buildUrl: BuildUrlFn; - connect: MethodFn; - delete: MethodFn; - get: MethodFn; getConfig: () => Config; - head: MethodFn; - options: MethodFn; - patch: MethodFn; - post: MethodFn; - put: MethodFn; request: RequestFn; setConfig: (config: Config) => Config; - trace: MethodFn; -} +} & { + [K in HttpMethod]: MethodFn; +} & ([SseFn] extends [never] ? { sse?: never } : { sse: { [K in HttpMethod]: SseFn } }); export interface Config { /** @@ -47,7 +42,7 @@ export interface Config { * * {@link https://developer.mozilla.org/docs/Web/API/fetch#method See more} */ - method?: "CONNECT" | "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PUT" | "TRACE"; + method?: Uppercase; /** * A function for serializing request query parameters. By default, arrays * will be exploded in form style, objects will be exploded in deepObject diff --git a/app/client/api-client/core/utils.gen.ts b/app/client/api-client/core/utils.gen.ts new file mode 100644 index 00000000..7e48839f --- /dev/null +++ b/app/client/api-client/core/utils.gen.ts @@ -0,0 +1,137 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import type { BodySerializer, QuerySerializer } from "./bodySerializer.gen"; +import { + type ArraySeparatorStyle, + serializeArrayParam, + serializeObjectParam, + serializePrimitiveParam, +} from "./pathSerializer.gen"; + +export interface PathSerializer { + 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"; + + 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"; + } + + const value = path[name]; + + if (value === undefined || value === null) { + 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 (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; +}; + +export const getUrl = ({ + baseUrl, + path, + query, + querySerializer, + url: _url, +}: { + 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; +}; + +export function getValidRequestBody(options: { + body?: unknown; + bodySerializer?: BodySerializer | null; + serializedBody?: unknown; +}) { + const hasBody = options.body !== undefined; + const isSerializedBody = hasBody && options.bodySerializer; + + if (isSerializedBody) { + if ("serializedBody" in options) { + const hasSerializedBody = options.serializedBody !== undefined && options.serializedBody !== ""; + + return hasSerializedBody ? options.serializedBody : 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; + } + + // no body was provided + return undefined; +} diff --git a/app/api-client/index.ts b/app/client/api-client/index.ts similarity index 69% rename from app/api-client/index.ts rename to app/client/api-client/index.ts index da870793..7a716924 100644 --- a/app/api-client/index.ts +++ b/app/client/api-client/index.ts @@ -1,3 +1,4 @@ // This file is auto-generated by @hey-api/openapi-ts -export * from "./types.gen"; + +export type * from "./types.gen"; export * from "./sdk.gen"; diff --git a/app/api-client/sdk.gen.ts b/app/client/api-client/sdk.gen.ts similarity index 78% rename from app/api-client/sdk.gen.ts rename to app/client/api-client/sdk.gen.ts index 824ca976..891623b5 100644 --- a/app/api-client/sdk.gen.ts +++ b/app/client/api-client/sdk.gen.ts @@ -1,92 +1,92 @@ // This file is auto-generated by @hey-api/openapi-ts -import type { Options as ClientOptions, TDataShape, Client } from "./client"; +import type { Client, Options as Options2, TDataShape } from "./client"; +import { client } from "./client.gen"; import type { - RegisterData, - RegisterResponses, + BrowseFilesystemData, + BrowseFilesystemResponses, + ChangePasswordData, + ChangePasswordResponses, + CreateBackupScheduleData, + CreateBackupScheduleResponses, + CreateRepositoryData, + CreateRepositoryResponses, + CreateVolumeData, + CreateVolumeResponses, + DeleteBackupScheduleData, + DeleteBackupScheduleResponses, + DeleteRepositoryData, + DeleteRepositoryResponses, + DeleteVolumeData, + DeleteVolumeResponses, + DoctorRepositoryData, + DoctorRepositoryResponses, + DownloadResticPasswordData, + DownloadResticPasswordResponses, + GetBackupScheduleData, + GetBackupScheduleForVolumeData, + GetBackupScheduleForVolumeResponses, + GetBackupScheduleResponses, + GetContainersUsingVolumeData, + GetContainersUsingVolumeErrors, + GetContainersUsingVolumeResponses, + GetMeData, + GetMeResponses, + GetRepositoryData, + GetRepositoryResponses, + GetSnapshotDetailsData, + GetSnapshotDetailsResponses, + GetStatusData, + GetStatusResponses, + GetSystemInfoData, + GetSystemInfoResponses, + GetVolumeData, + GetVolumeErrors, + GetVolumeResponses, + HealthCheckVolumeData, + HealthCheckVolumeErrors, + HealthCheckVolumeResponses, + ListBackupSchedulesData, + ListBackupSchedulesResponses, + ListFilesData, + ListFilesResponses, + ListRcloneRemotesData, + ListRcloneRemotesResponses, + ListRepositoriesData, + ListRepositoriesResponses, + ListSnapshotFilesData, + ListSnapshotFilesResponses, + ListSnapshotsData, + ListSnapshotsResponses, + ListVolumesData, + ListVolumesResponses, LoginData, LoginResponses, LogoutData, LogoutResponses, - GetMeData, - GetMeResponses, - GetStatusData, - GetStatusResponses, - ChangePasswordData, - ChangePasswordResponses, - ListVolumesData, - ListVolumesResponses, - CreateVolumeData, - CreateVolumeResponses, - TestConnectionData, - TestConnectionResponses, - DeleteVolumeData, - DeleteVolumeResponses, - GetVolumeData, - GetVolumeResponses, - GetVolumeErrors, - UpdateVolumeData, - UpdateVolumeResponses, - UpdateVolumeErrors, - GetContainersUsingVolumeData, - GetContainersUsingVolumeResponses, - GetContainersUsingVolumeErrors, MountVolumeData, MountVolumeResponses, - UnmountVolumeData, - UnmountVolumeResponses, - HealthCheckVolumeData, - HealthCheckVolumeResponses, - HealthCheckVolumeErrors, - ListFilesData, - ListFilesResponses, - BrowseFilesystemData, - BrowseFilesystemResponses, - ListRepositoriesData, - ListRepositoriesResponses, - CreateRepositoryData, - CreateRepositoryResponses, - ListRcloneRemotesData, - ListRcloneRemotesResponses, - DeleteRepositoryData, - DeleteRepositoryResponses, - GetRepositoryData, - GetRepositoryResponses, - ListSnapshotsData, - ListSnapshotsResponses, - GetSnapshotDetailsData, - GetSnapshotDetailsResponses, - ListSnapshotFilesData, - ListSnapshotFilesResponses, + RegisterData, + RegisterResponses, RestoreSnapshotData, RestoreSnapshotResponses, - DoctorRepositoryData, - DoctorRepositoryResponses, - ListBackupSchedulesData, - ListBackupSchedulesResponses, - CreateBackupScheduleData, - CreateBackupScheduleResponses, - DeleteBackupScheduleData, - DeleteBackupScheduleResponses, - GetBackupScheduleData, - GetBackupScheduleResponses, - UpdateBackupScheduleData, - UpdateBackupScheduleResponses, - GetBackupScheduleForVolumeData, - GetBackupScheduleForVolumeResponses, RunBackupNowData, RunBackupNowResponses, StopBackupData, - StopBackupResponses, StopBackupErrors, - GetSystemInfoData, - GetSystemInfoResponses, - DownloadResticPasswordData, - DownloadResticPasswordResponses, + StopBackupResponses, + TestConnectionData, + TestConnectionResponses, + UnmountVolumeData, + UnmountVolumeResponses, + UpdateBackupScheduleData, + UpdateBackupScheduleResponses, + UpdateVolumeData, + UpdateVolumeErrors, + UpdateVolumeResponses, } from "./types.gen"; -import { client as _heyApiClient } from "./client.gen"; -export type Options = ClientOptions< +export type Options = Options2< TData, ThrowOnError > & { @@ -107,7 +107,7 @@ export type Options(options?: Options) => { - return (options?.client ?? _heyApiClient).post({ + return (options?.client ?? client).post({ url: "/api/v1/auth/register", ...options, headers: { @@ -121,7 +121,7 @@ export const register = (options?: Options * Login with username and password */ export const login = (options?: Options) => { - return (options?.client ?? _heyApiClient).post({ + return (options?.client ?? client).post({ url: "/api/v1/auth/login", ...options, headers: { @@ -135,7 +135,7 @@ export const login = (options?: Options(options?: Options) => { - return (options?.client ?? _heyApiClient).post({ + return (options?.client ?? client).post({ url: "/api/v1/auth/logout", ...options, }); @@ -145,7 +145,7 @@ export const logout = (options?: Options(options?: Options) => { - return (options?.client ?? _heyApiClient).get({ + return (options?.client ?? client).get({ url: "/api/v1/auth/me", ...options, }); @@ -155,7 +155,7 @@ export const getMe = (options?: Options(options?: Options) => { - return (options?.client ?? _heyApiClient).get({ + return (options?.client ?? client).get({ url: "/api/v1/auth/status", ...options, }); @@ -167,7 +167,7 @@ export const getStatus = (options?: Option export const changePassword = ( options?: Options, ) => { - return (options?.client ?? _heyApiClient).post({ + return (options?.client ?? client).post({ url: "/api/v1/auth/change-password", ...options, headers: { @@ -181,7 +181,7 @@ export const changePassword = ( * List all volumes */ export const listVolumes = (options?: Options) => { - return (options?.client ?? _heyApiClient).get({ + return (options?.client ?? client).get({ url: "/api/v1/volumes", ...options, }); @@ -193,7 +193,7 @@ export const listVolumes = (options?: Opti export const createVolume = ( options?: Options, ) => { - return (options?.client ?? _heyApiClient).post({ + return (options?.client ?? client).post({ url: "/api/v1/volumes", ...options, headers: { @@ -209,7 +209,7 @@ export const createVolume = ( export const testConnection = ( options?: Options, ) => { - return (options?.client ?? _heyApiClient).post({ + return (options?.client ?? client).post({ url: "/api/v1/volumes/test-connection", ...options, headers: { @@ -225,7 +225,7 @@ export const testConnection = ( export const deleteVolume = ( options: Options, ) => { - return (options.client ?? _heyApiClient).delete({ + return (options.client ?? client).delete({ url: "/api/v1/volumes/{name}", ...options, }); @@ -235,7 +235,7 @@ export const deleteVolume = ( * Get a volume by name */ export const getVolume = (options: Options) => { - return (options.client ?? _heyApiClient).get({ + return (options.client ?? client).get({ url: "/api/v1/volumes/{name}", ...options, }); @@ -247,7 +247,7 @@ export const getVolume = (options: Options export const updateVolume = ( options: Options, ) => { - return (options.client ?? _heyApiClient).put({ + return (options.client ?? client).put({ url: "/api/v1/volumes/{name}", ...options, headers: { @@ -263,7 +263,7 @@ export const updateVolume = ( export const getContainersUsingVolume = ( options: Options, ) => { - return (options.client ?? _heyApiClient).get< + return (options.client ?? client).get< GetContainersUsingVolumeResponses, GetContainersUsingVolumeErrors, ThrowOnError @@ -277,7 +277,7 @@ export const getContainersUsingVolume = ( * Mount a volume */ export const mountVolume = (options: Options) => { - return (options.client ?? _heyApiClient).post({ + return (options.client ?? client).post({ url: "/api/v1/volumes/{name}/mount", ...options, }); @@ -289,7 +289,7 @@ export const mountVolume = (options: Optio export const unmountVolume = ( options: Options, ) => { - return (options.client ?? _heyApiClient).post({ + return (options.client ?? client).post({ url: "/api/v1/volumes/{name}/unmount", ...options, }); @@ -301,7 +301,7 @@ export const unmountVolume = ( export const healthCheckVolume = ( options: Options, ) => { - return (options.client ?? _heyApiClient).post({ + return (options.client ?? client).post({ url: "/api/v1/volumes/{name}/health-check", ...options, }); @@ -311,7 +311,7 @@ export const healthCheckVolume = ( * List files in a volume directory */ export const listFiles = (options: Options) => { - return (options.client ?? _heyApiClient).get({ + return (options.client ?? client).get({ url: "/api/v1/volumes/{name}/files", ...options, }); @@ -323,7 +323,7 @@ export const listFiles = (options: Options export const browseFilesystem = ( options?: Options, ) => { - return (options?.client ?? _heyApiClient).get({ + return (options?.client ?? client).get({ url: "/api/v1/volumes/filesystem/browse", ...options, }); @@ -335,7 +335,7 @@ export const browseFilesystem = ( export const listRepositories = ( options?: Options, ) => { - return (options?.client ?? _heyApiClient).get({ + return (options?.client ?? client).get({ url: "/api/v1/repositories", ...options, }); @@ -347,7 +347,7 @@ export const listRepositories = ( export const createRepository = ( options?: Options, ) => { - return (options?.client ?? _heyApiClient).post({ + return (options?.client ?? client).post({ url: "/api/v1/repositories", ...options, headers: { @@ -363,7 +363,7 @@ export const createRepository = ( export const listRcloneRemotes = ( options?: Options, ) => { - return (options?.client ?? _heyApiClient).get({ + return (options?.client ?? client).get({ url: "/api/v1/repositories/rclone-remotes", ...options, }); @@ -375,7 +375,7 @@ export const listRcloneRemotes = ( export const deleteRepository = ( options: Options, ) => { - return (options.client ?? _heyApiClient).delete({ + return (options.client ?? client).delete({ url: "/api/v1/repositories/{name}", ...options, }); @@ -387,7 +387,7 @@ export const deleteRepository = ( export const getRepository = ( options: Options, ) => { - return (options.client ?? _heyApiClient).get({ + return (options.client ?? client).get({ url: "/api/v1/repositories/{name}", ...options, }); @@ -399,7 +399,7 @@ export const getRepository = ( export const listSnapshots = ( options: Options, ) => { - return (options.client ?? _heyApiClient).get({ + return (options.client ?? client).get({ url: "/api/v1/repositories/{name}/snapshots", ...options, }); @@ -411,7 +411,7 @@ export const listSnapshots = ( export const getSnapshotDetails = ( options: Options, ) => { - return (options.client ?? _heyApiClient).get({ + return (options.client ?? client).get({ url: "/api/v1/repositories/{name}/snapshots/{snapshotId}", ...options, }); @@ -423,7 +423,7 @@ export const getSnapshotDetails = ( export const listSnapshotFiles = ( options: Options, ) => { - return (options.client ?? _heyApiClient).get({ + return (options.client ?? client).get({ url: "/api/v1/repositories/{name}/snapshots/{snapshotId}/files", ...options, }); @@ -435,7 +435,7 @@ export const listSnapshotFiles = ( export const restoreSnapshot = ( options: Options, ) => { - return (options.client ?? _heyApiClient).post({ + return (options.client ?? client).post({ url: "/api/v1/repositories/{name}/restore", ...options, headers: { @@ -451,7 +451,7 @@ export const restoreSnapshot = ( export const doctorRepository = ( options: Options, ) => { - return (options.client ?? _heyApiClient).post({ + return (options.client ?? client).post({ url: "/api/v1/repositories/{name}/doctor", ...options, }); @@ -463,7 +463,7 @@ export const doctorRepository = ( export const listBackupSchedules = ( options?: Options, ) => { - return (options?.client ?? _heyApiClient).get({ + return (options?.client ?? client).get({ url: "/api/v1/backups", ...options, }); @@ -475,7 +475,7 @@ export const listBackupSchedules = ( export const createBackupSchedule = ( options?: Options, ) => { - return (options?.client ?? _heyApiClient).post({ + return (options?.client ?? client).post({ url: "/api/v1/backups", ...options, headers: { @@ -491,7 +491,7 @@ export const createBackupSchedule = ( export const deleteBackupSchedule = ( options: Options, ) => { - return (options.client ?? _heyApiClient).delete({ + return (options.client ?? client).delete({ url: "/api/v1/backups/{scheduleId}", ...options, }); @@ -503,7 +503,7 @@ export const deleteBackupSchedule = ( export const getBackupSchedule = ( options: Options, ) => { - return (options.client ?? _heyApiClient).get({ + return (options.client ?? client).get({ url: "/api/v1/backups/{scheduleId}", ...options, }); @@ -515,7 +515,7 @@ export const getBackupSchedule = ( export const updateBackupSchedule = ( options: Options, ) => { - return (options.client ?? _heyApiClient).patch({ + return (options.client ?? client).patch({ url: "/api/v1/backups/{scheduleId}", ...options, headers: { @@ -531,7 +531,7 @@ export const updateBackupSchedule = ( export const getBackupScheduleForVolume = ( options: Options, ) => { - return (options.client ?? _heyApiClient).get({ + return (options.client ?? client).get({ url: "/api/v1/backups/volume/{volumeId}", ...options, }); @@ -543,7 +543,7 @@ export const getBackupScheduleForVolume = export const runBackupNow = ( options: Options, ) => { - return (options.client ?? _heyApiClient).post({ + return (options.client ?? client).post({ url: "/api/v1/backups/{scheduleId}/run", ...options, }); @@ -553,7 +553,7 @@ export const runBackupNow = ( * Stop a backup that is currently in progress */ export const stopBackup = (options: Options) => { - return (options.client ?? _heyApiClient).post({ + return (options.client ?? client).post({ url: "/api/v1/backups/{scheduleId}/stop", ...options, }); @@ -565,7 +565,7 @@ export const stopBackup = (options: Option export const getSystemInfo = ( options?: Options, ) => { - return (options?.client ?? _heyApiClient).get({ + return (options?.client ?? client).get({ url: "/api/v1/system/info", ...options, }); @@ -577,7 +577,7 @@ export const getSystemInfo = ( export const downloadResticPassword = ( options?: Options, ) => { - return (options?.client ?? _heyApiClient).post({ + return (options?.client ?? client).post({ url: "/api/v1/system/restic-password", ...options, headers: { diff --git a/app/api-client/types.gen.ts b/app/client/api-client/types.gen.ts similarity index 100% rename from app/api-client/types.gen.ts rename to app/client/api-client/types.gen.ts index 27a92158..2f5bca86 100644 --- a/app/api-client/types.gen.ts +++ b/app/client/api-client/types.gen.ts @@ -1,5 +1,9 @@ // This file is auto-generated by @hey-api/openapi-ts +export type ClientOptions = { + baseUrl: "http://192.168.2.42:4096" | (string & {}); +}; + export type RegisterData = { body?: { password: string; @@ -1672,7 +1676,3 @@ export type DownloadResticPasswordResponses = { }; export type DownloadResticPasswordResponse = DownloadResticPasswordResponses[keyof DownloadResticPasswordResponses]; - -export type ClientOptions = { - baseUrl: "http://192.168.2.42:4096" | (string & {}); -}; diff --git a/app/client/components/ui/badge.tsx b/app/client/components/ui/badge.tsx index d7528722..e98a53b9 100644 --- a/app/client/components/ui/badge.tsx +++ b/app/client/components/ui/badge.tsx @@ -2,7 +2,7 @@ import type * as React from "react"; import { Slot } from "@radix-ui/react-slot"; import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "~/lib/utils"; +import { cn } from "~/client/lib/utils"; const badgeVariants = cva( "inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", diff --git a/drizzle/0000_known_madelyne_pryor.sql b/app/drizzle/0000_known_madelyne_pryor.sql similarity index 100% rename from drizzle/0000_known_madelyne_pryor.sql rename to app/drizzle/0000_known_madelyne_pryor.sql diff --git a/drizzle/0001_far_frank_castle.sql b/app/drizzle/0001_far_frank_castle.sql similarity index 100% rename from drizzle/0001_far_frank_castle.sql rename to app/drizzle/0001_far_frank_castle.sql diff --git a/drizzle/0002_cheerful_randall.sql b/app/drizzle/0002_cheerful_randall.sql similarity index 100% rename from drizzle/0002_cheerful_randall.sql rename to app/drizzle/0002_cheerful_randall.sql diff --git a/drizzle/0003_mature_hellcat.sql b/app/drizzle/0003_mature_hellcat.sql similarity index 100% rename from drizzle/0003_mature_hellcat.sql rename to app/drizzle/0003_mature_hellcat.sql diff --git a/drizzle/0004_wealthy_tomas.sql b/app/drizzle/0004_wealthy_tomas.sql similarity index 100% rename from drizzle/0004_wealthy_tomas.sql rename to app/drizzle/0004_wealthy_tomas.sql diff --git a/drizzle/0005_simple_alice.sql b/app/drizzle/0005_simple_alice.sql similarity index 100% rename from drizzle/0005_simple_alice.sql rename to app/drizzle/0005_simple_alice.sql diff --git a/drizzle/0006_secret_micromacro.sql b/app/drizzle/0006_secret_micromacro.sql similarity index 100% rename from drizzle/0006_secret_micromacro.sql rename to app/drizzle/0006_secret_micromacro.sql diff --git a/drizzle/0007_watery_sersi.sql b/app/drizzle/0007_watery_sersi.sql similarity index 100% rename from drizzle/0007_watery_sersi.sql rename to app/drizzle/0007_watery_sersi.sql diff --git a/drizzle/0008_silent_lady_bullseye.sql b/app/drizzle/0008_silent_lady_bullseye.sql similarity index 100% rename from drizzle/0008_silent_lady_bullseye.sql rename to app/drizzle/0008_silent_lady_bullseye.sql diff --git a/drizzle/0009_little_adam_warlock.sql b/app/drizzle/0009_little_adam_warlock.sql similarity index 100% rename from drizzle/0009_little_adam_warlock.sql rename to app/drizzle/0009_little_adam_warlock.sql diff --git a/drizzle/0010_perfect_proemial_gods.sql b/app/drizzle/0010_perfect_proemial_gods.sql similarity index 100% rename from drizzle/0010_perfect_proemial_gods.sql rename to app/drizzle/0010_perfect_proemial_gods.sql diff --git a/drizzle/meta/0000_snapshot.json b/app/drizzle/meta/0000_snapshot.json similarity index 100% rename from drizzle/meta/0000_snapshot.json rename to app/drizzle/meta/0000_snapshot.json diff --git a/drizzle/meta/0001_snapshot.json b/app/drizzle/meta/0001_snapshot.json similarity index 100% rename from drizzle/meta/0001_snapshot.json rename to app/drizzle/meta/0001_snapshot.json diff --git a/drizzle/meta/0002_snapshot.json b/app/drizzle/meta/0002_snapshot.json similarity index 100% rename from drizzle/meta/0002_snapshot.json rename to app/drizzle/meta/0002_snapshot.json diff --git a/drizzle/meta/0003_snapshot.json b/app/drizzle/meta/0003_snapshot.json similarity index 100% rename from drizzle/meta/0003_snapshot.json rename to app/drizzle/meta/0003_snapshot.json diff --git a/drizzle/meta/0004_snapshot.json b/app/drizzle/meta/0004_snapshot.json similarity index 100% rename from drizzle/meta/0004_snapshot.json rename to app/drizzle/meta/0004_snapshot.json diff --git a/drizzle/meta/0005_snapshot.json b/app/drizzle/meta/0005_snapshot.json similarity index 100% rename from drizzle/meta/0005_snapshot.json rename to app/drizzle/meta/0005_snapshot.json diff --git a/drizzle/meta/0006_snapshot.json b/app/drizzle/meta/0006_snapshot.json similarity index 100% rename from drizzle/meta/0006_snapshot.json rename to app/drizzle/meta/0006_snapshot.json diff --git a/drizzle/meta/0007_snapshot.json b/app/drizzle/meta/0007_snapshot.json similarity index 100% rename from drizzle/meta/0007_snapshot.json rename to app/drizzle/meta/0007_snapshot.json diff --git a/drizzle/meta/0008_snapshot.json b/app/drizzle/meta/0008_snapshot.json similarity index 100% rename from drizzle/meta/0008_snapshot.json rename to app/drizzle/meta/0008_snapshot.json diff --git a/drizzle/meta/0009_snapshot.json b/app/drizzle/meta/0009_snapshot.json similarity index 100% rename from drizzle/meta/0009_snapshot.json rename to app/drizzle/meta/0009_snapshot.json diff --git a/drizzle/meta/0010_snapshot.json b/app/drizzle/meta/0010_snapshot.json similarity index 100% rename from drizzle/meta/0010_snapshot.json rename to app/drizzle/meta/0010_snapshot.json diff --git a/drizzle/meta/_journal.json b/app/drizzle/meta/_journal.json similarity index 100% rename from drizzle/meta/_journal.json rename to app/drizzle/meta/_journal.json diff --git a/app/server/index.ts b/app/server/index.ts index e7ddc322..a603bed0 100644 --- a/app/server/index.ts +++ b/app/server/index.ts @@ -105,4 +105,4 @@ process.on("SIGINT", async () => { process.exit(0); }); -export default await createHonoServer({ app }); +export default await createHonoServer({ app, port: 4096 }); diff --git a/bun.lock b/bun.lock index 9b1c62b2..0a55a7bf 100644 --- a/bun.lock +++ b/bun.lock @@ -56,12 +56,15 @@ "yaml": "^2.8.1", }, "devDependencies": { + "@hey-api/openapi-ts": "^0.87.4", "@react-router/dev": "^7.9.3", "@tailwindcss/vite": "^4.1.14", + "@types/bun": "^1.3.2", "@types/dockerode": "^3.3.45", "@types/node": "^24.6.2", "@types/react": "^19.2.0", "@types/react-dom": "^19.2.0", + "drizzle-kit": "^0.31.6", "lightningcss": "^1.30.2", "tailwindcss": "^4.1.14", "tinyglobby": "^0.2.15", @@ -140,7 +143,11 @@ "@dabh/diagnostics": ["@dabh/diagnostics@2.0.8", "", { "dependencies": { "@so-ric/colorspace": "^1.1.6", "enabled": "2.0.x", "kuler": "^2.0.0" } }, "sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q=="], - "@drizzle-team/brocli": ["@drizzle-team/brocli@0.11.0", "", {}, "sha512-hD3pekGiPg0WPCCGAZmusBBJsDqGUR66Y452YgQsZOnkdQ7ViEPKuyP4huUGEZQefp8g34RRodXYmJ2TbCH+tg=="], + "@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="], + + "@esbuild-kit/core-utils": ["@esbuild-kit/core-utils@3.3.2", "", { "dependencies": { "esbuild": "~0.18.20", "source-map-support": "^0.5.21" } }, "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ=="], + + "@esbuild-kit/esm-loader": ["@esbuild-kit/esm-loader@2.6.5", "", { "dependencies": { "@esbuild-kit/core-utils": "^3.3.2", "get-tsconfig": "^4.7.0" } }, "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA=="], "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], @@ -206,6 +213,12 @@ "@grpc/proto-loader": ["@grpc/proto-loader@0.7.15", "", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.2.5", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ=="], + "@hey-api/codegen-core": ["@hey-api/codegen-core@0.3.3", "", { "peerDependencies": { "typescript": ">=5.5.3" } }, "sha512-vArVDtrvdzFewu1hnjUm4jX1NBITlSCeO81EdWq676MxQbyxsGcDPAgohaSA+Wvr4HjPSvsg2/1s2zYxUtXebg=="], + + "@hey-api/json-schema-ref-parser": ["@hey-api/json-schema-ref-parser@1.2.1", "", { "dependencies": { "@jsdevtools/ono": "^7.1.3", "@types/json-schema": "^7.0.15", "js-yaml": "^4.1.0", "lodash": "^4.17.21" } }, "sha512-inPeksRLq+j3ArnuGOzQPQE//YrhezQG0+9Y9yizScBN2qatJ78fIByhEgKdNAbtguDCn4RPxmEhcrePwHxs4A=="], + + "@hey-api/openapi-ts": ["@hey-api/openapi-ts@0.87.4", "", { "dependencies": { "@hey-api/codegen-core": "^0.3.3", "@hey-api/json-schema-ref-parser": "1.2.1", "ansi-colors": "4.1.3", "c12": "3.3.2", "color-support": "1.1.3", "commander": "14.0.1", "open": "10.2.0", "semver": "7.7.2" }, "peerDependencies": { "typescript": ">=5.5.3" }, "bin": { "openapi-ts": "bin/run.js" } }, "sha512-ogSjR7l+PCBoRvvJVrUFZ3Cv4GDnETpwAr5G9EwsbjKVJHZDsQn3EIOYJi2WqKl9VPZBT1CtycIxR/ZmCS/T4A=="], + "@hono/node-server": ["@hono/node-server@1.19.6", "", { "peerDependencies": { "hono": "^4" } }, "sha512-Shz/KjlIeAhfiuE93NDKVdZ7HdBVLQAfdbaXEaoAVO3ic9ibRSLGIQGkcBbFyuLr+7/1D5ZCINM8B+6IvXeMtw=="], "@hono/node-ws": ["@hono/node-ws@1.2.0", "", { "dependencies": { "ws": "^8.17.0" }, "peerDependencies": { "@hono/node-server": "^1.11.1", "hono": "^4.6.0" } }, "sha512-OBPQ8OSHBw29mj00wT/xGYtB6HY54j0fNSdVZ7gZM3TUeq0So11GXaWtFf1xWxQNfumKIsj0wRuLKWfVsO5GgQ=="], @@ -230,6 +243,8 @@ "@js-sdsl/ordered-map": ["@js-sdsl/ordered-map@4.4.2", "", {}, "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw=="], + "@jsdevtools/ono": ["@jsdevtools/ono@7.1.3", "", {}, "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg=="], + "@mjackson/node-fetch-server": ["@mjackson/node-fetch-server@0.2.0", "", {}, "sha512-EMlH1e30yzmTpGLQjlFmaDAjyOeZhng1/XCd7DExR8PNAnG/G1tyruZxEoUe11ClnwGhGrtsdnyyUx1frSzjng=="], "@npmcli/git": ["@npmcli/git@4.1.0", "", { "dependencies": { "@npmcli/promise-spawn": "^6.0.0", "lru-cache": "^7.4.4", "npm-pick-manifest": "^8.0.0", "proc-log": "^3.0.0", "promise-inflight": "^1.0.1", "promise-retry": "^2.0.1", "semver": "^7.3.5", "which": "^3.0.0" } }, "sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ=="], @@ -452,6 +467,8 @@ "@tanstack/table-core": ["@tanstack/table-core@8.21.3", "", {}, "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg=="], + "@types/bun": ["@types/bun@1.3.2", "", { "dependencies": { "bun-types": "1.3.2" } }, "sha512-t15P7k5UIgHKkxwnMNkJbWlh/617rkDGEdSsDbu+qNHTaz9SKf7aC8fiIlUdD5RPpH6GEkP0cK7WlvmrEBRtWg=="], + "@types/d3-array": ["@types/d3-array@3.2.2", "", {}, "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw=="], "@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="], @@ -492,12 +509,16 @@ "accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="], + "ansi-colors": ["ansi-colors@4.1.3", "", {}, "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw=="], + "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "arg": ["arg@5.0.2", "", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="], + "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + "aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="], "arkregex": ["arkregex@0.0.2", "", { "dependencies": { "@ark/util": "0.53.0" } }, "sha512-ttjDUICBVoXD/m8bf7eOjx8XMR6yIT2FmmW9vsN0FCcFOygEZvvIX8zK98tTdXkzi0LkRi5CmadB44jFEIyDNA=="], @@ -536,8 +557,14 @@ "buildcheck": ["buildcheck@0.0.6", "", {}, "sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A=="], + "bun-types": ["bun-types@1.3.2", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-i/Gln4tbzKNuxP70OWhJRZz1MRfvqExowP7U6JKoI8cntFrtxg7RJK3jvz7wQW54UuvNC8tbKHHri5fy74FVqg=="], + + "bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="], + "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], + "c12": ["c12@3.3.2", "", { "dependencies": { "chokidar": "^4.0.3", "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-QkikB2X5voO1okL3QsES0N690Sn/K9WokXqUsDQsWy5SnYb+psYQFGA10iy1bZHj3fjISKsI67Q90gruvWWM3A=="], + "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], @@ -550,6 +577,8 @@ "chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="], + "citty": ["citty@0.1.6", "", { "dependencies": { "consola": "^3.2.3" } }, "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ=="], + "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="], "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], @@ -564,10 +593,18 @@ "color-string": ["color-string@2.1.2", "", { "dependencies": { "color-name": "^2.0.0" } }, "sha512-RxmjYxbWemV9gKu4zPgiZagUxbH3RQpEIO77XoSSX0ivgABDZ+h8Zuash/EMFLTI4N9QgFPOJ6JQpPZKFxa+dA=="], + "color-support": ["color-support@1.1.3", "", { "bin": { "color-support": "bin.js" } }, "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg=="], + + "commander": ["commander@14.0.1", "", {}, "sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A=="], + "compressible": ["compressible@2.0.18", "", { "dependencies": { "mime-db": ">= 1.43.0 < 2" } }, "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg=="], "compression": ["compression@1.8.1", "", { "dependencies": { "bytes": "3.1.2", "compressible": "~2.0.18", "debug": "2.6.9", "negotiator": "~0.6.4", "on-headers": "~1.1.0", "safe-buffer": "5.2.1", "vary": "~1.1.2" } }, "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w=="], + "confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], + + "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], + "content-disposition": ["content-disposition@0.5.4", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ=="], "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], @@ -616,8 +653,18 @@ "dedent": ["dedent@1.7.0", "", { "peerDependencies": { "babel-plugin-macros": "^3.1.0" }, "optionalPeers": ["babel-plugin-macros"] }, "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ=="], + "default-browser": ["default-browser@5.3.0", "", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-Qq68+VkJlc8tjnPV1i7HtbIn7ohmjZa88qUvHMIK0ZKUXMCuV45cT7cEXALPUmeXCe0q1DWQkQTemHVaLIFSrg=="], + + "default-browser-id": ["default-browser-id@5.0.0", "", {}, "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA=="], + + "define-lazy-prop": ["define-lazy-prop@3.0.0", "", {}, "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg=="], + + "defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], + "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], + "destr": ["destr@2.0.5", "", {}, "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA=="], + "destroy": ["destroy@1.2.0", "", {}, "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="], "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], @@ -632,6 +679,8 @@ "dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="], + "drizzle-kit": ["drizzle-kit@0.31.6", "", { "dependencies": { "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.25.4", "esbuild-register": "^3.5.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-/B4e/4pwnx25QwD5xXgdpo1S+077a2VZdosXbItE/oNmUgQwZydGDz9qJYmnQl/b+5IX0rLfwRhrPnroGtrg8Q=="], + "drizzle-orm": ["drizzle-orm@0.44.7", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@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": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-quIpnYznjU9lHshEOAYLoZ9s3jweleHlZIAWR/jX9gAWNg/JhQ1wj0KGRf7/Zm+obRrYd9GjPVJg790QY9N5AQ=="], "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], @@ -666,6 +715,8 @@ "esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], + "esbuild-register": ["esbuild-register@3.6.0", "", { "dependencies": { "debug": "^4.3.4" }, "peerDependencies": { "esbuild": ">=0.12 <1" } }, "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg=="], + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], @@ -678,6 +729,8 @@ "express": ["express@4.21.2", "", { "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA=="], + "exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="], + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], "fecha": ["fecha@4.2.3", "", {}, "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="], @@ -710,6 +763,10 @@ "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + "get-tsconfig": ["get-tsconfig@4.13.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ=="], + + "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=="], + "glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], "globrex": ["globrex@0.1.2", "", {}, "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg=="], @@ -746,10 +803,16 @@ "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], + "is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="], + "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + "is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="], + "is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], + "is-wsl": ["is-wsl@3.1.0", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw=="], + "isbot": ["isbot@5.1.32", "", {}, "sha512-VNfjM73zz2IBZmdShMfAUg10prm6t7HFUQmNAEOAVS4YH92ZrZcvkMcGX6cIgBJAzWDzPent/EeAtYEHNPNPBQ=="], "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], @@ -760,6 +823,8 @@ "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], + "jsesc": ["jsesc@3.0.2", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g=="], "json-parse-even-better-errors": ["json-parse-even-better-errors@3.0.2", "", {}, "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ=="], @@ -842,6 +907,8 @@ "node-cron": ["node-cron@4.2.1", "", {}, "sha512-lgimEHPE/QDgFlywTd8yTR61ptugX3Qer29efeyWw2rv259HtGBNn1vZVmp8lB9uo9wC0t/AT4iGqXxia+CJFg=="], + "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="], + "node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="], "normalize-package-data": ["normalize-package-data@5.0.0", "", { "dependencies": { "hosted-git-info": "^6.0.0", "is-core-module": "^2.8.1", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4" } }, "sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q=="], @@ -854,8 +921,12 @@ "npm-pick-manifest": ["npm-pick-manifest@8.0.2", "", { "dependencies": { "npm-install-checks": "^6.0.0", "npm-normalize-package-bin": "^3.0.0", "npm-package-arg": "^10.0.0", "semver": "^7.3.5" } }, "sha512-1dKY+86/AIiq1tkKVD3l0WI+Gd3vkknVGAggsFeBkTvbhMQ1OND/LKkYv4JtXPKUJ8bOTCyLiqEg2P6QNdK+Gg=="], + "nypm": ["nypm@0.6.2", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.2", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "tinyexec": "^1.0.1" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g=="], + "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], + "ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], + "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], "on-headers": ["on-headers@1.1.0", "", {}, "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A=="], @@ -864,6 +935,8 @@ "one-time": ["one-time@1.0.0", "", { "dependencies": { "fn.name": "1.x.x" } }, "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g=="], + "open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="], + "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="], "p-map": ["p-map@7.0.4", "", {}, "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ=="], @@ -880,10 +953,14 @@ "pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="], + "perfect-debounce": ["perfect-debounce@2.0.0", "", {}, "sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow=="], + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + "pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], + "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], "prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="], @@ -908,6 +985,8 @@ "raw-body": ["raw-body@2.5.2", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" } }, "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA=="], + "rc9": ["rc9@2.1.2", "", { "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" } }, "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg=="], + "react": ["react@19.2.0", "", {}, "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ=="], "react-dom": ["react-dom@19.2.0", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" } }, "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ=="], @@ -944,10 +1023,14 @@ "reselect": ["reselect@5.1.1", "", {}, "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w=="], + "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], + "retry": ["retry@0.12.0", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="], "rollup": ["rollup@4.53.2", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.53.2", "@rollup/rollup-android-arm64": "4.53.2", "@rollup/rollup-darwin-arm64": "4.53.2", "@rollup/rollup-darwin-x64": "4.53.2", "@rollup/rollup-freebsd-arm64": "4.53.2", "@rollup/rollup-freebsd-x64": "4.53.2", "@rollup/rollup-linux-arm-gnueabihf": "4.53.2", "@rollup/rollup-linux-arm-musleabihf": "4.53.2", "@rollup/rollup-linux-arm64-gnu": "4.53.2", "@rollup/rollup-linux-arm64-musl": "4.53.2", "@rollup/rollup-linux-loong64-gnu": "4.53.2", "@rollup/rollup-linux-ppc64-gnu": "4.53.2", "@rollup/rollup-linux-riscv64-gnu": "4.53.2", "@rollup/rollup-linux-riscv64-musl": "4.53.2", "@rollup/rollup-linux-s390x-gnu": "4.53.2", "@rollup/rollup-linux-x64-gnu": "4.53.2", "@rollup/rollup-linux-x64-musl": "4.53.2", "@rollup/rollup-openharmony-arm64": "4.53.2", "@rollup/rollup-win32-arm64-msvc": "4.53.2", "@rollup/rollup-win32-ia32-msvc": "4.53.2", "@rollup/rollup-win32-x64-gnu": "4.53.2", "@rollup/rollup-win32-x64-msvc": "4.53.2", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-MHngMYwGJVi6Fmnk6ISmnk7JAHRNF0UkuucA0CUW3N3a4KnONPEZz+vUanQP/ZC/iY1Qkf3bwPWzyY84wEks1g=="], + "run-applescript": ["run-applescript@7.1.0", "", {}, "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q=="], + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], "safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="], @@ -956,7 +1039,7 @@ "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], - "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + "semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], "send": ["send@0.19.0", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "2.4.1", "range-parser": "~1.2.1", "statuses": "2.0.1" } }, "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw=="], @@ -1034,6 +1117,8 @@ "tiny-typed-emitter": ["tiny-typed-emitter@2.1.0", "", {}, "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA=="], + "tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="], + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], @@ -1104,6 +1189,8 @@ "ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="], + "wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="], + "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], @@ -1122,6 +1209,8 @@ "@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="], + "@grpc/grpc-js/@grpc/proto-loader": ["@grpc/proto-loader@0.8.0", "", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.5.3", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, "sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ=="], "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], @@ -1132,6 +1221,10 @@ "@npmcli/git/lru-cache": ["lru-cache@7.18.3", "", {}, "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="], + "@npmcli/git/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + + "@npmcli/package-json/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=="], "@radix-ui/react-collection/@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=="], @@ -1152,6 +1245,8 @@ "@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=="], + "@react-router/dev/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + "@scalar/types/nanoid": ["nanoid@5.1.5", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.7.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-pJdKGq/1iquWYtv1RRSljZklxHCOCAJFJrImO5ZLKPJVJlVUcs8yFwNQlqS0Lo8xT1VAXXTCZocF9n26FWEKsw=="], @@ -1178,6 +1273,8 @@ "body-parser/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + "c12/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "compression/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], @@ -1188,6 +1285,8 @@ "finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + "giget/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "hosted-git-info/lru-cache": ["lru-cache@7.18.3", "", {}, "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="], "mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], @@ -1196,14 +1295,72 @@ "morgan/on-finished": ["on-finished@2.3.0", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww=="], + "normalize-package-data/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + + "npm-install-checks/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + + "npm-package-arg/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + + "npm-pick-manifest/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + + "nypm/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + "pkg-types/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + + "react-router-hono-server/@drizzle-team/brocli": ["@drizzle-team/brocli@0.11.0", "", {}, "sha512-hD3pekGiPg0WPCCGAZmusBBJsDqGUR66Y452YgQsZOnkdQ7ViEPKuyP4huUGEZQefp8g34RRodXYmJ2TbCH+tg=="], + "send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "send/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="], "vite-node/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "@esbuild-kit/core-utils/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.18.20", "", { "os": "android", "cpu": "arm64" }, "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.18.20", "", { "os": "android", "cpu": "x64" }, "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.18.20", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.18.20", "", { "os": "darwin", "cpu": "x64" }, "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.18.20", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.18.20", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.18.20", "", { "os": "linux", "cpu": "arm" }, "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.18.20", "", { "os": "linux", "cpu": "arm64" }, "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.18.20", "", { "os": "linux", "cpu": "ia32" }, "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.18.20", "", { "os": "linux", "cpu": "ppc64" }, "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.18.20", "", { "os": "linux", "cpu": "s390x" }, "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.18.20", "", { "os": "linux", "cpu": "x64" }, "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.18.20", "", { "os": "none", "cpu": "x64" }, "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.18.20", "", { "os": "openbsd", "cpu": "x64" }, "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.18.20", "", { "os": "sunos", "cpu": "x64" }, "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.18.20", "", { "os": "win32", "cpu": "arm64" }, "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.18.20", "", { "os": "win32", "cpu": "ia32" }, "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="], + "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], "@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], diff --git a/drizzle.config.ts b/drizzle.config.ts index 5b01ceba..6f1e1b5c 100644 --- a/drizzle.config.ts +++ b/drizzle.config.ts @@ -2,8 +2,8 @@ import "dotenv/config"; import { defineConfig } from "drizzle-kit"; export default defineConfig({ - out: "./apps/server/drizzle", - schema: "./apps/server/src/db/schema.ts", + out: "./app/drizzle", + schema: "./app/server/db/schema.ts", dialect: "sqlite", dbCredentials: { url: "./data/ironmount.db", diff --git a/openapi-ts.config.ts b/openapi-ts.config.ts index 5331d2ca..08a16687 100644 --- a/openapi-ts.config.ts +++ b/openapi-ts.config.ts @@ -3,7 +3,7 @@ import { defaultPlugins, defineConfig } from "@hey-api/openapi-ts"; export default defineConfig({ input: "http://192.168.2.42:4096/api/v1/openapi.json", output: { - path: "./apps/client/app/api-client", + path: "./app/client/api-client", format: "biome", }, plugins: [...defaultPlugins, "@tanstack/react-query", "@hey-api/client-fetch"], diff --git a/package.json b/package.json index 45cd071b..5c38e133 100644 --- a/package.json +++ b/package.json @@ -67,12 +67,15 @@ "yaml": "^2.8.1" }, "devDependencies": { + "@hey-api/openapi-ts": "^0.87.4", "@react-router/dev": "^7.9.3", "@tailwindcss/vite": "^4.1.14", + "@types/bun": "^1.3.2", "@types/dockerode": "^3.3.45", "@types/node": "^24.6.2", "@types/react": "^19.2.0", "@types/react-dom": "^19.2.0", + "drizzle-kit": "^0.31.6", "lightningcss": "^1.30.2", "tailwindcss": "^4.1.14", "tinyglobby": "^0.2.15",